├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── bin └── build.js ├── composer.json ├── package-lock.json ├── postcss.config.cjs ├── resources ├── css │ ├── index.css │ └── treeselectjs.css ├── dist │ ├── filament-select-tree.css │ └── filament-select-tree.js ├── images │ ├── example-1.jpg │ ├── example-2.jpg │ ├── example-3.jpg │ └── thumbnail.jpg ├── js │ └── index.js ├── lang │ └── en │ │ └── select-tree.php └── views │ └── select-tree.blade.php └── src ├── FilamentSelectTreeServiceProvider.php ├── SelectTree.php └── Testing └── TestsFilamentSelectTree.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `filament-select-tree` will be documented in this file. 4 | 5 | ## 1.0.0 - 202X-XX-XX 6 | 7 | - initial release 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) CodeWithDennis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Filament Select Tree 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/codewithdennis/filament-select-tree.svg?style=flat-square)](https://packagist.org/packages/codewithdennis/filament-select-tree) 4 | [![Total Downloads](https://img.shields.io/packagist/dt/codewithdennis/filament-select-tree.svg?style=flat-square)](https://packagist.org/packages/codewithdennis/filament-select-tree) 5 | 6 | This package adds a dynamic select tree field to your Laravel / Filament application, allowing you to create interactive hierarchical selection dropdowns based on relationships. It's handy for 7 | building selection dropdowns with various customization options. 8 | 9 | ![thumbnail](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/thumbnail.jpg) 10 | 11 | ## Installation 12 | 13 | You can install the package via composer: 14 | 15 | ```bash 16 | composer require codewithdennis/filament-select-tree 17 | ``` 18 | 19 | ```bash 20 | php artisan filament:assets 21 | ``` 22 | 23 | ## Relationships 24 | 25 | Use the tree for a `BelongsToMany` relationship 26 | 27 | ```php 28 | SelectTree::make('categories') 29 | ->relationship('categories', 'name', 'parent_id') 30 | ``` 31 | 32 | Use the tree for a `BelongsTo` relationship 33 | 34 | ```php 35 | SelectTree::make('category_id') 36 | ->relationship('category', 'name', 'parent_id') 37 | ``` 38 | 39 | ## Custom Query 40 | 41 | Customize the parent query 42 | 43 | ```php 44 | SelectTree::make('categories') 45 | ->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyQueryUsing: fn($query) => $query)); 46 | ``` 47 | 48 | Customize the child query 49 | 50 | ```php 51 | SelectTree::make('categories') 52 | ->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyChildQueryUsing: fn($query) => $query)); 53 | ``` 54 | 55 | ## Methods 56 | 57 | Set a custom placeholder when no items are selected 58 | 59 | ```php 60 | ->placeholder(__('Please select a category')) 61 | ``` 62 | 63 | Enable the selection of groups 64 | 65 | ```php 66 | ->enableBranchNode() 67 | ``` 68 | 69 | Customize the label when there are zero search results 70 | 71 | ```php 72 | ->emptyLabel(__('Oops, no results have been found!')) 73 | ``` 74 | 75 | Display the count of children alongside the group's name 76 | 77 | ```php 78 | ->withCount() 79 | ``` 80 | 81 | Keep the dropdown open at all times 82 | 83 | ```php 84 | ->alwaysOpen() 85 | ``` 86 | 87 | Set nodes as dependent 88 | 89 | ```php 90 | ->independent(false) 91 | ``` 92 | 93 | Expand the tree with selected values (only works if field is dependent) 94 | 95 | ```php 96 | ->expandSelected(false) 97 | ``` 98 | 99 | Set the parent's null value to -1, allowing you to use -1 as a sentinel value (default = null) 100 | 101 | ```php 102 | ->parentNullValue(-1) 103 | ``` 104 | 105 | All groups will be opened to this level 106 | 107 | ```php 108 | ->defaultOpenLevel(2) 109 | ``` 110 | 111 | Specify the list's force direction. Options include: auto (default), top, and bottom. 112 | 113 | ```php 114 | ->direction('top') 115 | ``` 116 | 117 | Display individual leaf nodes instead of the main group when all leaf nodes are selected 118 | 119 | ```php 120 | ->grouped(false) 121 | ``` 122 | 123 | Hide the clearable icon 124 | 125 | ```php 126 | ->clearable(false) 127 | ``` 128 | 129 | Activate the search functionality 130 | 131 | ```php 132 | ->searchable(); 133 | ``` 134 | 135 | Disable specific options in the tree 136 | 137 | ```php 138 | ->disabledOptions([2, 3, 4]) 139 | ``` 140 | 141 | Hide specific options in the tree 142 | 143 | ```php 144 | ->hiddenOptions([2, 3, 4]) 145 | ``` 146 | 147 | Allow soft deleted items to be displayed 148 | 149 | ```php 150 | ->withTrashed() 151 | ``` 152 | 153 | Specify a different key for your model. 154 | For example: you have id, code and parent_code. Your model uses id as key, but the parent-child relation is established between code and parent_code 155 | 156 | ```php 157 | ->withKey('code') 158 | ``` 159 | 160 | Store fetched models for additional functionality 161 | 162 | ```php 163 | ->storeResults() 164 | ``` 165 | 166 | Now you can access the results in `disabledOptions` or `hiddenOptions` 167 | 168 | ```php 169 | ->disabledOptions(function ($state, SelectTree $component) { 170 | $results = $component->getResults(); 171 | }) 172 | ``` 173 | 174 | By default, the type of selection in the tree (single or multiple) is determined by the relationship type: `BelongsTo` for single selection and `BelongsToMany` for multiple selection. If you want to 175 | explicitly set the selection type, use: 176 | 177 | ```php 178 | ->multiple(false) 179 | ``` 180 | 181 | you can change the tree key with the following method. 182 | 183 | ```php 184 | ->treeKey('my-cool-tree') 185 | ``` 186 | 187 | If you need to prepend an item to the tree menu, use the `prepend` method. This method accepts an array or a closure. It is useful when the tree-select is used as a filter (see example below). 188 | 189 | ```php 190 | use Filament\Tables\Filters\Filter; 191 | use Illuminate\Database\Eloquent\Builder; 192 | use CodeWithDennis\FilamentSelectTree\SelectTree; 193 | ``` 194 | 195 | ```php 196 | ->filters([ 197 | Filter::make('tree') 198 | ->form([ 199 | SelectTree::make('category') 200 | ->relationship('categories', 'name', 'parent_id') 201 | ->enableBranchNode() 202 | ->multiple(false) 203 | ->prepend([ 204 | 'name' => 'Uncategorized Records', 205 | 'value' => -1, 206 | 'parent' => null, // optional 207 | 'disabled' => false, // optional 208 | 'hidden' => false, // optional 209 | 'children' => [], // optional 210 | ]) 211 | ]) 212 | ->query(function (Builder $query, array $data) { 213 | return $query->when($data['categories'], function (Builder $query, $categories) { 214 | if (collect($categories)->contains('-1')) { 215 | $query->whereDoesntHave('categories'); 216 | } 217 | return $query->orWhereHas('categories', 218 | fn(Builder $query) => $query->whereIn('id', $categories)); 219 | }); 220 | }) 221 | ]) 222 | ``` 223 | 224 | ## Filters 225 | 226 | Use the tree in your table filters. Here's an example to show you how. 227 | 228 | ```bash 229 | use Filament\Tables\Filters\Filter; 230 | use Illuminate\Database\Eloquent\Builder; 231 | use CodeWithDennis\FilamentSelectTree\SelectTree; 232 | ``` 233 | 234 | ```php 235 | ->filters([ 236 | Filter::make('tree') 237 | ->form([ 238 | SelectTree::make('categories') 239 | ->relationship('categories', 'name', 'parent_id') 240 | ->independent(false) 241 | ->enableBranchNode(), 242 | ]) 243 | ->query(function (Builder $query, array $data) { 244 | return $query->when($data['categories'], function ($query, $categories) { 245 | return $query->whereHas('categories', fn($query) => $query->whereIn('id', $categories)); 246 | }); 247 | }) 248 | ->indicateUsing(function (array $data): ?string { 249 | if (! $data['categories']) { 250 | return null; 251 | } 252 | 253 | return __('Categories') . ': ' . implode(', ', Category::whereIn('id', $data['categories'])->get()->pluck('name')->toArray()); 254 | }) 255 | ]) 256 | ``` 257 | 258 | ## Screenshots 259 | 260 | ![example-1](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-1.jpg) 261 | ![example-2](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-2.jpg) 262 | ![example-3](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-3.jpg) 263 | 264 | ## Contributing 265 | 266 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. 267 | 268 | ## Security Vulnerabilities 269 | 270 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 271 | 272 | ## Credits 273 | 274 | - [CodeWithDennis](https://github.com/CodeWithDennis) 275 | - [Dipson88](https://github.com/dipson88/treeselectjs) 276 | - [All Contributors](../../contributors) 277 | 278 | ## License 279 | 280 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 281 | -------------------------------------------------------------------------------- /bin/build.js: -------------------------------------------------------------------------------- 1 | import * as esbuild from 'esbuild' 2 | 3 | const isDev = process.argv.includes('--dev') 4 | 5 | async function compile(options) { 6 | const context = await esbuild.context(options) 7 | 8 | if (isDev) { 9 | await context.watch() 10 | } else { 11 | await context.rebuild() 12 | await context.dispose() 13 | } 14 | } 15 | 16 | const defaultOptions = { 17 | define: { 18 | 'process.env.NODE_ENV': isDev ? `'development'` : `'production'`, 19 | }, 20 | bundle: true, 21 | mainFields: ['module', 'main'], 22 | platform: 'neutral', 23 | sourcemap: isDev ? 'inline' : false, 24 | sourcesContent: isDev, 25 | treeShaking: true, 26 | target: ['es2020'], 27 | minify: !isDev, 28 | plugins: [{ 29 | name: 'watchPlugin', 30 | setup: function (build) { 31 | build.onStart(() => { 32 | console.log(`Build started at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`) 33 | }) 34 | 35 | build.onEnd((result) => { 36 | if (result.errors.length > 0) { 37 | console.log(`Build failed at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`, result.errors) 38 | } else { 39 | console.log(`Build finished at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`) 40 | } 41 | }) 42 | } 43 | }], 44 | } 45 | 46 | compile({ 47 | ...defaultOptions, 48 | entryPoints: ['./resources/js/index.js'], 49 | outfile: './resources/dist/filament-select-tree.js', 50 | }) 51 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codewithdennis/filament-select-tree", 3 | "description": "The multi-level select field enables you to make single selections from a predefined list of options that are organized into multiple levels or depths.", 4 | "keywords": [ 5 | "CodeWithDennis", 6 | "laravel", 7 | "filament-select-tree", 8 | "filament", 9 | "tree" 10 | ], 11 | "homepage": "https://github.com/codewithdennis/filament-select-tree", 12 | "support": { 13 | "issues": "https://github.com/codewithdennis/filament-select-tree/issues", 14 | "source": "https://github.com/codewithdennis/filament-select-tree" 15 | }, 16 | "license": "MIT", 17 | "authors": [ 18 | { 19 | "name": "CodeWithDennis", 20 | "role": "Developer" 21 | } 22 | ], 23 | "require": { 24 | "php": "^8.1", 25 | "filament/forms": "^3.0", 26 | "spatie/laravel-package-tools": "^1.15.0", 27 | "illuminate/contracts": "^10.0|^11.0|^12.0" 28 | }, 29 | "require-dev": { 30 | "nunomaduro/collision": "^7.9", 31 | "orchestra/testbench": "^8.0|^9.0|^10.0", 32 | "pestphp/pest": "^2.0|^3.7", 33 | "pestphp/pest-plugin-arch": "^2.0|^3.0", 34 | "pestphp/pest-plugin-laravel": "^2.0|^3.1" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "CodeWithDennis\\FilamentSelectTree\\": "src/" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | "CodeWithDennis\\FilamentSelectTree\\Tests\\": "tests/" 44 | } 45 | }, 46 | "scripts": { 47 | "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", 48 | "test": "vendor/bin/pest", 49 | "test-coverage": "vendor/bin/pest --coverage" 50 | }, 51 | "config": { 52 | "sort-packages": true, 53 | "allow-plugins": { 54 | "pestphp/pest-plugin": true, 55 | "phpstan/extension-installer": true 56 | } 57 | }, 58 | "extra": { 59 | "laravel": { 60 | "providers": [ 61 | "CodeWithDennis\\FilamentSelectTree\\FilamentSelectTreeServiceProvider" 62 | ] 63 | } 64 | }, 65 | "minimum-stability": "dev", 66 | "prefer-stable": true 67 | } 68 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import')(), 4 | require('postcss-nesting')(), 5 | require('cssnano')({ 6 | preset: 'default', 7 | }), 8 | ], 9 | }; 10 | -------------------------------------------------------------------------------- /resources/css/index.css: -------------------------------------------------------------------------------- 1 | @import './treeselectjs.css'; 2 | 3 | .treeselect-input { 4 | font-size: 0.875rem; 5 | color: rgba(var(--gray-950), var(--tw-text-opacity)); 6 | transition-duration: 75ms; 7 | border-style: none; 8 | line-height: 1.5rem; 9 | outline: 2px solid transparent; 10 | outline-offset: 2px; 11 | background: transparent; 12 | } 13 | 14 | html.dark .treeselect > .treeselect-input { 15 | color: rgb(255 255 255 / var(--tw-text-opacity)) !important; 16 | } 17 | 18 | .treeselect-input--opened.treeselect-input--bottom { 19 | border: inherit; 20 | border-radius: inherit; 21 | } 22 | 23 | .treeselect-input__edit { 24 | background: transparent; 25 | } 26 | 27 | .treeselect-list__empty-icon { 28 | display: none; 29 | } 30 | 31 | .treeselect-input__edit::placeholder, .treeselect-list__empty { 32 | --tw-text-opacity: 1; 33 | color: rgba(var(--gray-400), var(--tw-text-opacity)); 34 | cursor: default; 35 | } 36 | 37 | .treeselect-input__clear svg { 38 | display: none; 39 | } 40 | 41 | .treeselect-input__clear { 42 | background-color: transparent; 43 | background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMSIgaGVpZ2h0PSIyMSI+PGcgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJtMi41OTIuMDQ0IDE4LjM2NCAxOC4zNjQtMi41NDggMi41NDhMLjA0NCAyLjU5MnoiLz48cGF0aCBkPSJNMCAxOC4zNjQgMTguMzY0IDBsMi41NDggMi41NDhMMi41NDggMjAuOTEyeiIvPjwvZz48L3N2Zz4='); 44 | background-position: 50%; 45 | background-repeat: no-repeat; 46 | background-size: .7142em .7142em; 47 | border-width: 0; 48 | inset-inline-end: 0; 49 | margin-inline-end: 2.25rem; 50 | opacity: .5; 51 | outline: 2px solid transparent; 52 | outline-offset: 2px; 53 | padding: 0; 54 | position: absolute; 55 | text-indent: -9999px; 56 | top: calc(50% - 0.38em); 57 | transition-duration: 75ms; 58 | transition-property: opacity; 59 | transition-timing-function: cubic-bezier(.4,0,.2,1); 60 | width: 1rem; 61 | height: 10px; 62 | } 63 | 64 | .dark .treeselect-input__clear { 65 | background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg=='); 66 | } 67 | 68 | .treeselect-list__empty { 69 | padding-top: 18px; 70 | padding-bottom: 18px; 71 | } 72 | 73 | .treeselect-input__tags-count { 74 | margin-left: 9px; 75 | } 76 | 77 | .treeselect-list { 78 | font-size: 0.875rem; 79 | line-height: 1.25rem; 80 | margin-top: 0.5rem; 81 | border-radius: 0.5rem; 82 | padding: 0.25rem; 83 | --tw-bg-opacity: 1; 84 | --tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 85 | 0 4px 6px -4px rgba(0, 0, 0, 0.1); 86 | --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 87 | 0 4px 6px -4px var(--tw-shadow-color); 88 | --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 89 | var(--tw-ring-offset-width) var(--tw-ring-offset-color); 90 | --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 91 | calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); 92 | --tw-ring-color: rgba(var(--gray-950), 0.05); 93 | background-color: rgb(255 255 255 / var(--tw-bg-opacity)); 94 | border-radius: 0.5rem; 95 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), 96 | var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 97 | box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), 98 | var(--tw-shadow, 0 0 #0000); 99 | border: none; 100 | } 101 | 102 | .treeselect-list__item { 103 | padding: 1.1rem; 104 | border-radius: 0.475rem; 105 | } 106 | 107 | .treeselect-list.treeselect-list--single-select 108 | .treeselect-list__item--single-selected { 109 | --tw-bg-opacity: 1; 110 | background-color: rgba(var(--gray-50), var(--tw-bg-opacity)) !important; 111 | } 112 | 113 | .treeselect-list__item:hover, 114 | .treeselect-list__item--focused { 115 | --tw-bg-opacity: 1; 116 | background-color: rgba(var(--gray-50), var(--tw-bg-opacity)) !important; 117 | } 118 | 119 | .treeselect-list.treeselect-list--single-select 120 | .treeselect-list__item--single-selected { 121 | font-weight: 500; 122 | } 123 | 124 | html.dark .treeselect-list { 125 | -tw-bg-opacity: 1; 126 | --tw-ring-color: hsla(0, 0%, 100%, 0.1); 127 | background-color: rgba(var(--gray-900), var(--tw-bg-opacity)); 128 | } 129 | 130 | html.dark .treeselect-list { 131 | -tw-bg-opacity: 1; 132 | --tw-ring-color: hsla(0, 0%, 100%, 0.1); 133 | background-color: rgba(var(--gray-900), var(--tw-bg-opacity)); 134 | } 135 | 136 | .treeselect-input__edit { 137 | border: transparent !important; 138 | --tw-ring-color: none !important; 139 | --tw-ring-shadow: none !important; 140 | } 141 | 142 | html.dark 143 | .treeselect-list.treeselect-list--single-select 144 | html.dark.treeselect-list__item--single-selected, 145 | html.dark .treeselect-list__item--focused, 146 | html.dark .treeselect-list__item:hover, 147 | html.dark 148 | .treeselect-list.treeselect-list--single-select 149 | .treeselect-list__item--single-selected, 150 | html.dark .treeselect-list__item--focused, 151 | html.dark .treeselect-list__item:hover { 152 | background-color: hsla(0, 0%, 100%, 0.05) !important; 153 | } 154 | 155 | html.dark .treeselect-list__item--checked, 156 | .treeselect-list__item--checked { 157 | background: transparent; 158 | } 159 | 160 | .treeselect-input__tags-element { 161 | --tw-bg-opacity: 1; 162 | --tw-text-opacity: 1; 163 | --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 164 | var(--tw-ring-offset-width) var(--tw-ring-offset-color); 165 | --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 166 | calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); 167 | --tw-ring-inset: inset; 168 | --tw-ring-color: rgba(var(--primary-600), 0.1); 169 | align-items: center; 170 | background-color: rgba(var(--primary-50), var(--tw-bg-opacity)); 171 | border-radius: 0.375rem; 172 | box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), 173 | var(--tw-shadow, 0 0 #0000); 174 | color: rgba(var(--primary-600), var(--tw-text-opacity)); 175 | display: inline-flex; 176 | font-size: 0.75rem; 177 | font-weight: 500; 178 | gap: 0.25rem; 179 | line-height: 1rem; 180 | padding: 0.25rem 0.5rem; 181 | word-break: break-all; 182 | } 183 | 184 | html.dark .treeselect-input__tags-element { 185 | --tw-text-opacity: 1; 186 | --tw-ring-color: rgba(var(--primary-400), 0.3); 187 | background-color: rgba(var(--primary-400), 0.1); 188 | color: rgba(var(--primary-400), var(--tw-text-opacity)); 189 | } 190 | 191 | .treeselect-list__item-checkbox-container { 192 | border-radius: 0.25rem; 193 | height: 16px; 194 | min-width: 16px; 195 | width: 16px; 196 | } 197 | 198 | .treeselect-list__item--checked .treeselect-list__item-checkbox-container, 199 | .treeselect-list__item--partial-checked 200 | .treeselect-list__item-checkbox-container { 201 | background-color: rgba(var(--primary-600), var(--tw-text-opacity)); 202 | } 203 | 204 | .treeselect-list__item-checkbox { 205 | transition-duration: 75ms; 206 | background-color: transparent !important; 207 | border: none; 208 | } 209 | 210 | .treeselect-list__item-checkbox-container { 211 | background-color: #f8f5f5; 212 | border: none; 213 | } 214 | 215 | html.dark .treeselect-list__item-checkbox-container { 216 | border: rgb(255 255 255 / var(--tw-text-opacity)); 217 | } 218 | 219 | html.dark .treeselect-list__item-checkbox-container { 220 | background-color: hsla(0, 0%, 100%, 0.05); 221 | } 222 | 223 | .treeselect-list__item-checkbox-icon { 224 | height: 80%; 225 | left: 0.1rem; 226 | top: 0.1rem; 227 | width: 80%; 228 | } 229 | 230 | .treeselect-input__tags-element:hover { 231 | background-color: rgba(var(--primary-50), var(--tw-bg-opacity)); 232 | } 233 | 234 | .treeselect-input__tags-element:hover .treeselect-input__tags-cross svg { 235 | stroke: rgba(var(--gray-950), var(--tw-text-opacity)); 236 | } 237 | 238 | html.dark 239 | .treeselect-input__tags-element:hover 240 | .treeselect-input__tags-cross 241 | svg { 242 | stroke: rgb(255 255 255 / var(--tw-text-opacity)); 243 | } 244 | 245 | .treeselect-input__tags-element { 246 | color: rgba(var(--primary-600), var(--tw-text-opacity)); 247 | } 248 | 249 | html.dark .treeselect-input__tags-element { 250 | color: rgba(var(--primary-400), var(--tw-text-opacity)); 251 | } 252 | 253 | html.dark .treeselect-input__tags-cross svg { 254 | stroke-width: 3px; 255 | } 256 | 257 | html.dark .treeselect-input__tags-cross svg { 258 | stroke: rgb(255 255 255 / var(--tw-text-opacity)); 259 | opacity: 0.5; 260 | } 261 | 262 | html.dark .treeselect-input__tags-element:hover svg { 263 | opacity: 0.6; 264 | } 265 | 266 | .treeselect-input__clear svg { 267 | opacity: 0.5; 268 | } 269 | 270 | .treeselect-input__tags { 271 | margin-left: 3px; 272 | } 273 | 274 | .treeselect--disabled .treeselect-input__tags-cross { 275 | display: none; 276 | } 277 | 278 | .treeselect--disabled .treeselect-input__arrow { 279 | display: none; 280 | } 281 | 282 | .treeselect-input__arrow { 283 | margin-right: 7px; 284 | } 285 | 286 | .treeselect--disabled .treeselect-input__clear { 287 | display: none; 288 | } 289 | 290 | .treeselect-list__item--disabled { 291 | cursor: not-allowed !important; 292 | } 293 | 294 | html.dark 295 | .treeselect-list__item--disabled 296 | .treeselect-list__item-checkbox-container { 297 | background-color: hsl(0deg 0% 30.77% / 5%); 298 | } 299 | 300 | [dir='rtl'] .treeselect-input__operators { 301 | left: 2px !important; 302 | right: unset; 303 | } 304 | 305 | [dir='rtl'] .treeselect-input { 306 | padding: 2px 4px 2px 40px; 307 | } 308 | 309 | .treeselect-input__arrow svg, .treeselect-input__arrow svg:hover { 310 | stroke: #6b7280; 311 | height: 20px; 312 | min-width: 18px; 313 | width: 15px; 314 | cursor: auto; 315 | } 316 | 317 | @media (max-width: 768px) { 318 | 319 | .treeselect-input, 320 | .treeselect-list, 321 | .treeselect-input__tags-element, 322 | .treeselect-input__tags-count, 323 | .treeselect-input__edit, 324 | .treeselect-list__item-label, 325 | .treeselect-list__item-label-counter, 326 | .treeselect-list__empty-text { 327 | font-size: 16px; 328 | } 329 | } 330 | 331 | [dir='rtl'] .treeselect-input__arrow { 332 | margin-left: 7px; 333 | } -------------------------------------------------------------------------------- /resources/css/treeselectjs.css: -------------------------------------------------------------------------------- 1 | .treeselect-input { 2 | width: 100%; 3 | box-sizing: border-box; 4 | border: 1px solid #d7dde4; 5 | border-radius: 4px; 6 | display: flex; 7 | align-items: center; 8 | flex-wrap: wrap; 9 | padding: 2px 40px 2px 4px; 10 | position: relative; 11 | min-height: 37px; 12 | background-color: #fff; 13 | cursor: text 14 | } 15 | 16 | .treeselect-input--unsearchable { 17 | cursor: default 18 | } 19 | 20 | .treeselect-input--unsearchable .treeselect-input__edit { 21 | caret-color: transparent; 22 | cursor: default 23 | } 24 | 25 | .treeselect-input--unsearchable .treeselect-input__edit:focus { 26 | position: absolute; 27 | z-index: -1; 28 | left: 0; 29 | min-width: 0; 30 | width: 0 31 | } 32 | 33 | .treeselect-input--value-not-selected .treeselect-input__edit, .treeselect-input--value-not-selected.treeselect-input--unsearchable .treeselect-input__edit:focus { 34 | z-index: auto; 35 | position: static; 36 | width: 100%; 37 | max-width: 100% 38 | } 39 | 40 | .treeselect-input--value-not-selected .treeselect-input__tags { 41 | gap: 0 42 | } 43 | 44 | [dir=rtl] .treeselect-input { 45 | padding-right: 4px; 46 | padding-left: 40px 47 | } 48 | 49 | [dir=rtl] .treeselect-input__operators { 50 | right: unset; 51 | left: 2px 52 | } 53 | 54 | .treeselect-input__tags { 55 | display: inline-flex; 56 | align-items: center; 57 | flex-wrap: wrap; 58 | gap: 4px; 59 | max-width: 100%; 60 | width: 100%; 61 | box-sizing: border-box 62 | } 63 | 64 | .treeselect-input__tags-element { 65 | display: inline-flex; 66 | align-items: center; 67 | background-color: #d7dde4; 68 | cursor: pointer; 69 | padding: 2px 5px; 70 | border-radius: 2px; 71 | font-size: 14px; 72 | max-width: 100%; 73 | box-sizing: border-box 74 | } 75 | 76 | .treeselect-input__tags-element:hover { 77 | background-color: #c5c7cb 78 | } 79 | 80 | .treeselect-input__tags-element:hover .treeselect-input__tags-cross svg { 81 | stroke: #eb4c42 82 | } 83 | 84 | .treeselect-input__tags-name { 85 | overflow: hidden; 86 | white-space: nowrap; 87 | text-overflow: ellipsis 88 | } 89 | 90 | .treeselect-input__tags-cross { 91 | display: flex; 92 | margin-left: 2px 93 | } 94 | 95 | .treeselect-input__tags-cross svg { 96 | width: 12px; 97 | height: 12px 98 | } 99 | 100 | .treeselect-input__tags-count { 101 | font-size: 14px; 102 | overflow: hidden; 103 | white-space: nowrap; 104 | text-overflow: ellipsis 105 | } 106 | 107 | .treeselect-input__edit { 108 | flex: 1; 109 | border: none; 110 | font-size: 14px; 111 | text-overflow: ellipsis; 112 | width: 100%; 113 | max-width: calc(100% - 45px); 114 | padding: 0; 115 | position: absolute; 116 | z-index: -1; 117 | min-width: 0 118 | } 119 | 120 | .treeselect-input__edit:focus { 121 | outline: none; 122 | min-width: 30px; 123 | max-width: 100%; 124 | z-index: auto; 125 | position: static 126 | } 127 | 128 | .treeselect-input__operators { 129 | display: flex; 130 | max-width: 40px; 131 | position: absolute; 132 | right: 2px 133 | } 134 | 135 | .treeselect-input__clear { 136 | display: flex; 137 | cursor: pointer 138 | } 139 | 140 | .treeselect-input__clear svg { 141 | stroke: #c5c7cb; 142 | width: 17px; 143 | min-width: 17px; 144 | height: 20px 145 | } 146 | 147 | .treeselect-input__clear:hover svg { 148 | stroke: #838790 149 | } 150 | 151 | .treeselect-input__arrow { 152 | display: flex; 153 | cursor: pointer 154 | } 155 | 156 | .treeselect-input__arrow svg { 157 | stroke: #c5c7cb; 158 | width: 20px; 159 | min-width: 20px; 160 | height: 20px 161 | } 162 | 163 | .treeselect-input__arrow:hover svg { 164 | stroke: #838790 165 | } 166 | 167 | .treeselect-list { 168 | width: 100%; 169 | box-sizing: border-box; 170 | border: 1px solid #d7dde4; 171 | overflow-y: auto; 172 | background-color: #fff; 173 | max-height: 300px 174 | } 175 | 176 | .treeselect-list__group-container { 177 | box-sizing: border-box 178 | } 179 | 180 | .treeselect-list__item { 181 | display: flex; 182 | align-items: center; 183 | box-sizing: border-box; 184 | cursor: pointer; 185 | height: 30px 186 | } 187 | 188 | .treeselect-list__item:focus { 189 | outline: none 190 | } 191 | 192 | .treeselect-list__item--focused { 193 | background-color: azure !important 194 | } 195 | 196 | .treeselect-list__item--hidden { 197 | display: none 198 | } 199 | 200 | .treeselect-list__item-icon { 201 | display: flex; 202 | align-items: center; 203 | cursor: pointer; 204 | height: 20px; 205 | width: 20px; 206 | min-width: 20px 207 | } 208 | 209 | .treeselect-list__item-icon svg { 210 | pointer-events: none; 211 | width: 100%; 212 | height: 100%; 213 | stroke: #c5c7cb 214 | } 215 | 216 | .treeselect-list__item-icon * { 217 | pointer-events: none 218 | } 219 | 220 | .treeselect-list__item-icon:hover svg { 221 | stroke: #838790 222 | } 223 | 224 | .treeselect-list__item-checkbox-container { 225 | width: 20px; 226 | height: 20px; 227 | min-width: 20px; 228 | border: 1px solid #d7dde4; 229 | border-radius: 3px; 230 | position: relative; 231 | background-color: #fff; 232 | pointer-events: none; 233 | box-sizing: border-box 234 | } 235 | 236 | .treeselect-list__item-checkbox-container svg { 237 | position: absolute; 238 | height: 100%; 239 | width: 100% 240 | } 241 | 242 | .treeselect-list__item-checkbox { 243 | margin: 0; 244 | width: 0; 245 | height: 0; 246 | pointer-events: none; 247 | position: absolute; 248 | z-index: -1 249 | } 250 | 251 | .treeselect-list__item-checkbox-icon { 252 | position: absolute; 253 | height: 100%; 254 | width: 100%; 255 | left: 0; 256 | top: 0; 257 | text-align: left 258 | } 259 | 260 | .treeselect-list__item-label { 261 | width: 100%; 262 | overflow: hidden; 263 | text-overflow: ellipsis; 264 | word-break: keep-all; 265 | white-space: nowrap; 266 | font-size: 14px; 267 | padding-left: 5px; 268 | pointer-events: none; 269 | text-align: left 270 | } 271 | 272 | .treeselect-list__item-label-counter { 273 | margin-left: 3px; 274 | color: #838790; 275 | font-size: 13px 276 | } 277 | 278 | .treeselect-list__empty { 279 | display: flex; 280 | align-items: center; 281 | height: 30px; 282 | padding-left: 4px 283 | } 284 | 285 | .treeselect-list__empty--hidden { 286 | display: none 287 | } 288 | 289 | .treeselect-list__empty-icon { 290 | display: flex; 291 | align-items: center 292 | } 293 | 294 | .treeselect-list__empty-text { 295 | font-size: 14px; 296 | padding-left: 5px; 297 | overflow: hidden; 298 | text-overflow: ellipsis; 299 | word-break: keep-all; 300 | white-space: nowrap 301 | } 302 | 303 | .treeselect-list__slot { 304 | position: sticky; 305 | box-sizing: border-box; 306 | width: 100%; 307 | max-width: 100%; 308 | bottom: 0; 309 | background-color: #fff 310 | } 311 | 312 | .treeselect-list.treeselect-list--single-select .treeselect-list__item-checkbox-container, .treeselect-list.treeselect-list--disabled-branch-node .treeselect-list__item--group .treeselect-list__item-checkbox-container { 313 | display: none 314 | } 315 | 316 | .treeselect-list__item--checked { 317 | background-color: #e9f1f1 318 | } 319 | 320 | .treeselect-list.treeselect-list--single-select .treeselect-list__item--checked { 321 | background-color: transparent 322 | } 323 | 324 | .treeselect-list.treeselect-list--single-select .treeselect-list__item--single-selected { 325 | background-color: #e9f1f1 326 | } 327 | 328 | .treeselect-list__item .treeselect-list__item-checkbox-container svg { 329 | stroke: transparent 330 | } 331 | 332 | .treeselect-list__item--checked .treeselect-list__item-checkbox-container svg, .treeselect-list__item--partial-checked .treeselect-list__item-checkbox-container svg { 333 | stroke: #fff 334 | } 335 | 336 | .treeselect-list__item--checked .treeselect-list__item-checkbox-container, .treeselect-list__item--partial-checked .treeselect-list__item-checkbox-container { 337 | background-color: #52c67e 338 | } 339 | 340 | .treeselect-list__item--disabled .treeselect-list__item-checkbox-container { 341 | background-color: #e9f1f1 342 | } 343 | 344 | .treeselect-list__item--disabled .treeselect-list__item-label { 345 | color: #c5c7cb 346 | } 347 | 348 | [dir=rtl] .treeselect-list__item-checkbox-icon { 349 | text-align: right 350 | } 351 | 352 | [dir=rtl] .treeselect-list__item-label { 353 | text-align: right; 354 | padding-right: 5px; 355 | padding-left: unset 356 | } 357 | 358 | [dir=rtl] .treeselect-list__item--closed .treeselect-list__item-icon { 359 | transform: rotate(180deg) 360 | } 361 | 362 | [dir=rtl] .treeselect-list__empty { 363 | padding-right: 4px; 364 | padding-left: unset 365 | } 366 | 367 | [dir=rtl] .treeselect-list__empty-text { 368 | padding-right: 5px; 369 | padding-left: unset 370 | } 371 | 372 | .treeselect { 373 | width: 100%; 374 | position: relative; 375 | box-sizing: border-box 376 | } 377 | 378 | .treeselect--disabled { 379 | pointer-events: none 380 | } 381 | 382 | .treeselect-list { 383 | position: absolute; 384 | left: 0; 385 | border-radius: 4px; 386 | box-sizing: border-box; 387 | z-index: 1000 388 | } 389 | 390 | .treeselect .treeselect-list { 391 | position: absolute 392 | } 393 | 394 | .treeselect .treeselect-list--static { 395 | position: static 396 | } 397 | 398 | .treeselect-input--focused { 399 | border-color: #101010 400 | } 401 | 402 | .treeselect-input--opened.treeselect-input--top { 403 | border-top-color: transparent; 404 | border-top-left-radius: 0; 405 | border-top-right-radius: 0 406 | } 407 | 408 | .treeselect-input--opened.treeselect-input--bottom { 409 | border-bottom-color: transparent; 410 | border-bottom-left-radius: 0; 411 | border-bottom-right-radius: 0 412 | } 413 | 414 | .treeselect-list--focused { 415 | border-color: #101010 416 | } 417 | 418 | .treeselect-list--top, .treeselect-list--top-to-body { 419 | border-bottom-color: #d7dde4; 420 | border-bottom-left-radius: 0; 421 | border-bottom-right-radius: 0 422 | } 423 | 424 | .treeselect-list--bottom, .treeselect-list--bottom-to-body { 425 | border-top-color: #d7dde4; 426 | border-top-left-radius: 0; 427 | border-top-right-radius: 0 428 | } 429 | 430 | .treeselect-list--top { 431 | left: 0; 432 | bottom: 100% 433 | } 434 | 435 | .treeselect-list--bottom { 436 | left: 0; 437 | top: 100% 438 | } -------------------------------------------------------------------------------- /resources/dist/filament-select-tree.css: -------------------------------------------------------------------------------- 1 | .treeselect-input{align-items:center;background-color:#fff;border:1px solid #d7dde4;border-radius:4px;box-sizing:border-box;cursor:text;display:flex;flex-wrap:wrap;min-height:37px;padding:2px 40px 2px 4px;position:relative;width:100%}.treeselect-input--unsearchable{cursor:default}.treeselect-input--unsearchable .treeselect-input__edit{caret-color:transparent;cursor:default}.treeselect-input--unsearchable .treeselect-input__edit:focus{left:0;min-width:0;position:absolute;width:0;z-index:-1}.treeselect-input--value-not-selected .treeselect-input__edit,.treeselect-input--value-not-selected.treeselect-input--unsearchable .treeselect-input__edit:focus{max-width:100%;position:static;width:100%;z-index:auto}.treeselect-input--value-not-selected .treeselect-input__tags{gap:0}[dir=rtl] .treeselect-input{padding-left:40px;padding-right:4px}[dir=rtl] .treeselect-input__operators{left:2px}.treeselect-input__tags{align-items:center;box-sizing:border-box;display:inline-flex;flex-wrap:wrap;gap:4px;max-width:100%;width:100%}.treeselect-input__tags-element{background-color:#d7dde4;border-radius:2px;box-sizing:border-box;cursor:pointer;font-size:14px;max-width:100%;padding:2px 5px}.treeselect-input__tags-element:hover{background-color:#c5c7cb}.treeselect-input__tags-element:hover .treeselect-input__tags-cross svg{stroke:#eb4c42}.treeselect-input__tags-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.treeselect-input__tags-cross{display:flex;margin-left:2px}.treeselect-input__tags-cross svg{height:12px;width:12px}.treeselect-input__tags-count{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.treeselect-input__edit{border:none;flex:1;font-size:14px;max-width:calc(100% - 45px);min-width:0;padding:0;position:absolute;text-overflow:ellipsis;width:100%;z-index:-1}.treeselect-input__edit:focus{max-width:100%;min-width:30px;outline:none;position:static;z-index:auto}.treeselect-input__operators{display:flex;max-width:40px;position:absolute;right:2px}.treeselect-input__clear{cursor:pointer;display:flex}.treeselect-input__clear svg{stroke:#c5c7cb;height:20px;min-width:17px;width:17px}.treeselect-input__clear:hover svg{stroke:#838790}.treeselect-input__arrow{cursor:pointer;display:flex}.treeselect-input__arrow svg{stroke:#c5c7cb;height:20px;min-width:20px;width:20px}.treeselect-input__arrow:hover svg{stroke:#838790}.treeselect-list{background-color:#fff;border:1px solid #d7dde4;max-height:300px;overflow-y:auto;width:100%}.treeselect-list__group-container{box-sizing:border-box}.treeselect-list__item{align-items:center;box-sizing:border-box;cursor:pointer;display:flex;height:30px}.treeselect-list__item:focus{outline:none}.treeselect-list__item--focused{background-color:azure!important}.treeselect-list__item--hidden{display:none}.treeselect-list__item-icon{align-items:center;cursor:pointer;display:flex;height:20px;min-width:20px;width:20px}.treeselect-list__item-icon svg{stroke:#c5c7cb;height:100%;pointer-events:none;width:100%}.treeselect-list__item-icon *{pointer-events:none}.treeselect-list__item-icon:hover svg{stroke:#838790}.treeselect-list__item-checkbox-container{background-color:#fff;border:1px solid #d7dde4;border-radius:3px;box-sizing:border-box;height:20px;min-width:20px;pointer-events:none;position:relative;width:20px}.treeselect-list__item-checkbox-container svg{height:100%;position:absolute;width:100%}.treeselect-list__item-checkbox{height:0;margin:0;pointer-events:none;position:absolute;width:0;z-index:-1}.treeselect-list__item-checkbox-icon{height:100%;left:0;position:absolute;text-align:left;top:0;width:100%}.treeselect-list__item-label{font-size:14px;overflow:hidden;padding-left:5px;pointer-events:none;text-align:left;text-overflow:ellipsis;white-space:nowrap;width:100%;word-break:keep-all}.treeselect-list__item-label-counter{color:#838790;font-size:13px;margin-left:3px}.treeselect-list__empty{align-items:center;display:flex;height:30px;padding-left:4px}.treeselect-list__empty--hidden{display:none}.treeselect-list__empty-icon{align-items:center;display:flex}.treeselect-list__empty-text{font-size:14px;overflow:hidden;padding-left:5px;text-overflow:ellipsis;white-space:nowrap;word-break:keep-all}.treeselect-list__slot{background-color:#fff;bottom:0;box-sizing:border-box;max-width:100%;position:sticky;width:100%}.treeselect-list.treeselect-list--disabled-branch-node .treeselect-list__item--group .treeselect-list__item-checkbox-container,.treeselect-list.treeselect-list--single-select .treeselect-list__item-checkbox-container{display:none}.treeselect-list__item--checked{background-color:#e9f1f1}.treeselect-list.treeselect-list--single-select .treeselect-list__item--checked{background-color:transparent}.treeselect-list.treeselect-list--single-select .treeselect-list__item--single-selected{background-color:#e9f1f1}.treeselect-list__item .treeselect-list__item-checkbox-container svg{stroke:transparent}.treeselect-list__item--checked .treeselect-list__item-checkbox-container svg,.treeselect-list__item--partial-checked .treeselect-list__item-checkbox-container svg{stroke:#fff}.treeselect-list__item--checked .treeselect-list__item-checkbox-container,.treeselect-list__item--partial-checked .treeselect-list__item-checkbox-container{background-color:#52c67e}.treeselect-list__item--disabled .treeselect-list__item-checkbox-container{background-color:#e9f1f1}.treeselect-list__item--disabled .treeselect-list__item-label{color:#c5c7cb}[dir=rtl] .treeselect-list__item-checkbox-icon{text-align:right}[dir=rtl] .treeselect-list__item-label{padding-left:unset;padding-right:5px;text-align:right}[dir=rtl] .treeselect-list__item--closed .treeselect-list__item-icon{transform:rotate(180deg)}[dir=rtl] .treeselect-list__empty{padding-left:unset;padding-right:4px}[dir=rtl] .treeselect-list__empty-text{padding-left:unset;padding-right:5px}.treeselect{box-sizing:border-box;position:relative;width:100%}.treeselect--disabled{pointer-events:none}.treeselect-list{border-radius:4px;box-sizing:border-box;left:0;z-index:1000}.treeselect .treeselect-list,.treeselect-list{position:absolute}.treeselect .treeselect-list--static{position:static}.treeselect-input--focused{border-color:#101010}.treeselect-input--opened.treeselect-input--top{border-top-color:transparent;border-top-left-radius:0;border-top-right-radius:0}.treeselect-input--opened.treeselect-input--bottom{border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0}.treeselect-list--focused{border-color:#101010}.treeselect-list--top,.treeselect-list--top-to-body{border-bottom-color:#d7dde4;border-bottom-left-radius:0;border-bottom-right-radius:0}.treeselect-list--bottom,.treeselect-list--bottom-to-body{border-top-color:#d7dde4;border-top-left-radius:0;border-top-right-radius:0}.treeselect-list--top{bottom:100%;left:0}.treeselect-list--bottom{left:0;top:100%}.treeselect-input{background:transparent;border-style:none;color:rgba(var(--gray-950),var(--tw-text-opacity));font-size:.875rem;line-height:1.5rem;outline:2px solid transparent;outline-offset:2px;transition-duration:75ms}html.dark .treeselect>.treeselect-input{color:rgb(255 255 255/var(--tw-text-opacity))!important}.treeselect-input--opened.treeselect-input--bottom{border:inherit;border-radius:inherit}.treeselect-input__edit{background:transparent}.treeselect-list__empty-icon{display:none}.treeselect-input__edit::placeholder,.treeselect-list__empty{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity));cursor:default}.treeselect-input__clear svg{display:none}.treeselect-input__clear{background-color:transparent;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMSIgaGVpZ2h0PSIyMSI+PGcgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJtMi41OTIuMDQ0IDE4LjM2NCAxOC4zNjQtMi41NDggMi41NDhMLjA0NCAyLjU5MnoiLz48cGF0aCBkPSJNMCAxOC4zNjQgMTguMzY0IDBsMi41NDggMi41NDhMMi41NDggMjAuOTEyeiIvPjwvZz48L3N2Zz4=");background-position:50%;background-repeat:no-repeat;background-size:.7142em .7142em;border-width:0;height:10px;inset-inline-end:0;margin-inline-end:2.25rem;opacity:.5;outline:2px solid transparent;outline-offset:2px;padding:0;position:absolute;text-indent:-9999px;top:calc(50% - .38em);transition-duration:75ms;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);width:1rem}.dark .treeselect-input__clear{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMSIgaGVpZ2h0PSIyMSI+PGcgZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJtMi41OTIuMDQ0IDE4LjM2NCAxOC4zNjQtMi41NDggMi41NDhMLjA0NCAyLjU5MnoiLz48cGF0aCBkPSJNMCAxOC4zNjQgMTguMzY0IDBsMi41NDggMi41NDhMMi41NDggMjAuOTEyeiIvPjwvZz48L3N2Zz4=")}.treeselect-list__empty{padding-bottom:18px;padding-top:18px}.treeselect-input__tags-count{margin-left:9px}.treeselect-list{--tw-bg-opacity:1;--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:rgba(var(--gray-950),0.05);background-color:rgb(255 255 255/var(--tw-bg-opacity));border:none;border-radius:.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);font-size:.875rem;line-height:1.25rem;margin-top:.5rem;padding:.25rem}.treeselect-list__item{border-radius:.475rem;padding:1.1rem}.treeselect-list.treeselect-list--single-select .treeselect-list__item--single-selected,.treeselect-list__item--focused,.treeselect-list__item:hover{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))!important}.treeselect-list.treeselect-list--single-select .treeselect-list__item--single-selected{font-weight:500}html.dark .treeselect-list{-tw-bg-opacity:1;--tw-ring-color:hsla(0,0%,100%,.1);background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}.treeselect-input__edit{--tw-ring-color:none!important;--tw-ring-shadow:none!important;border:transparent!important}html.dark .treeselect-list.treeselect-list--single-select .treeselect-list__item--single-selected,html.dark .treeselect-list.treeselect-list--single-select html.dark.treeselect-list__item--single-selected,html.dark .treeselect-list__item--focused,html.dark .treeselect-list__item:hover{background-color:hsla(0,0%,100%,.05)!important}.treeselect-list__item--checked,html.dark .treeselect-list__item--checked{background:transparent}.treeselect-input__tags-element{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-inset:inset;--tw-ring-color:rgba(var(--primary-600),0.1);align-items:center;background-color:rgba(var(--primary-50),var(--tw-bg-opacity));border-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);display:inline-flex;font-size:.75rem;font-weight:500;gap:.25rem;line-height:1rem;padding:.25rem .5rem;word-break:break-all}html.dark .treeselect-input__tags-element{--tw-text-opacity:1;--tw-ring-color:rgba(var(--primary-400),0.3);background-color:rgba(var(--primary-400),.1)}.treeselect-list__item-checkbox-container{border-radius:.25rem;height:16px;min-width:16px;width:16px}.treeselect-list__item--checked .treeselect-list__item-checkbox-container,.treeselect-list__item--partial-checked .treeselect-list__item-checkbox-container{background-color:rgba(var(--primary-600),var(--tw-text-opacity))}.treeselect-list__item-checkbox{background-color:transparent!important;border:none;transition-duration:75ms}.treeselect-list__item-checkbox-container{background-color:#f8f5f5;border:none}html.dark .treeselect-list__item-checkbox-container{background-color:hsla(0,0%,100%,.05);border:rgb(255 255 255/var(--tw-text-opacity))}.treeselect-list__item-checkbox-icon{height:80%;left:.1rem;top:.1rem;width:80%}.treeselect-input__tags-element:hover{background-color:rgba(var(--primary-50),var(--tw-bg-opacity))}.treeselect-input__tags-element:hover .treeselect-input__tags-cross svg{stroke:rgba(var(--gray-950),var(--tw-text-opacity))}html.dark .treeselect-input__tags-element:hover .treeselect-input__tags-cross svg{stroke:rgb(255 255 255/var(--tw-text-opacity))}.treeselect-input__tags-element{color:rgba(var(--primary-600),var(--tw-text-opacity))}html.dark .treeselect-input__tags-element{color:rgba(var(--primary-400),var(--tw-text-opacity))}html.dark .treeselect-input__tags-cross svg{stroke-width:3px;stroke:rgb(255 255 255/var(--tw-text-opacity));opacity:.5}html.dark .treeselect-input__tags-element:hover svg{opacity:.6}.treeselect-input__clear svg{opacity:.5}.treeselect-input__tags{margin-left:3px}.treeselect--disabled .treeselect-input__arrow,.treeselect--disabled .treeselect-input__tags-cross{display:none}.treeselect-input__arrow{margin-right:7px}.treeselect--disabled .treeselect-input__clear{display:none}.treeselect-list__item--disabled{cursor:not-allowed!important}html.dark .treeselect-list__item--disabled .treeselect-list__item-checkbox-container{background-color:rgba(78,78,78,.05)}[dir=rtl] .treeselect-input__operators{left:2px!important;right:unset}[dir=rtl] .treeselect-input{padding:2px 4px 2px 40px}.treeselect-input__arrow svg,.treeselect-input__arrow svg:hover{stroke:#6b7280;cursor:auto;height:20px;min-width:18px;width:15px}@media (max-width:768px){.treeselect-input,.treeselect-input__edit,.treeselect-input__tags-count,.treeselect-input__tags-element,.treeselect-list,.treeselect-list__empty-text,.treeselect-list__item-label,.treeselect-list__item-label-counter{font-size:16px}}[dir=rtl] .treeselect-input__arrow{margin-left:7px} -------------------------------------------------------------------------------- /resources/dist/filament-select-tree.js: -------------------------------------------------------------------------------- 1 | var Qt=Object.defineProperty,Ct=e=>{throw TypeError(e)},es=(e,t,s)=>t in e?Qt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s,a=(e,t,s)=>es(e,typeof t!="symbol"?t+"":t,s),Ee=(e,t,s)=>t.has(e)||Ct("Cannot "+s),l=(e,t,s)=>(Ee(e,t,"read from private field"),s?s.call(e):t.get(e)),k=(e,t,s)=>t.has(e)?Ct("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,s),E=(e,t,s,i)=>(Ee(e,t,"write to private field"),i?i.call(e,s):t.set(e,s),s),o=(e,t,s)=>(Ee(e,t,"access private method"),s),Se={arrowUp:'',arrowDown:'',arrowRight:'',attention:'',clear:'',cross:'',check:'',partialCheck:''},A=(e,t)=>{if(t.innerHTML="",typeof e=="string")t.innerHTML=e;else{let s=e.cloneNode(!0);t.appendChild(s)}},Te=e=>{let t=e?{...e}:{};return Object.keys(Se).forEach(s=>{t[s]||(t[s]=Se[s])}),t},ts=e=>e.reduce((t,{name:s},i)=>(t+=s,il(this,y).focus(),0)}blur(){this.isOpened&&o(this,u,G).call(this),this.clearSearch(),l(this,y).blur()}updateValue(t){this.value=t,o(this,u,q).call(this),o(this,u,z).call(this)}removeItem(t){this.value=this.value.filter(s=>s.id!==t),o(this,u,re).call(this),o(this,u,q).call(this),o(this,u,z).call(this)}clear(){this.value=[],o(this,u,re).call(this),o(this,u,q).call(this),this.clearSearch()}openClose(){o(this,u,G).call(this)}clearSearch(){this.searchText="",this.searchCallback(""),o(this,u,z).call(this)}};B=new WeakMap,y=new WeakMap,$=new WeakMap,T=new WeakMap,u=new WeakSet,wt=function(){o(this,u,q).call(this),o(this,u,z).call(this),o(this,u,ye).call(this)},q=function(){if(l(this,B).innerHTML="",this.showTags){l(this,B).append(...o(this,u,Ne).call(this));let e=ts(this.value);this.nameChangeCallback(e)}else{let e=o(this,u,Oe).call(this);l(this,B).appendChild(e),this.nameChangeCallback(e.innerText)}l(this,B).appendChild(l(this,y))},ye=function(){let e=[];l(this,$).innerHTML="",this.clearable&&e.push(o(this,u,Ve).call(this)),this.isAlwaysOpened||e.push(o(this,u,Ge).call(this,this.isOpened)),e.length&&l(this,$).append(...e)},xe=function(){if(!this.isAlwaysOpened&&l(this,T)){let e=this.isOpened?this.iconElements.arrowUp:this.iconElements.arrowDown;A(e,l(this,T))}},z=function(){var e;(e=this.value)!=null&&e.length?(l(this,y).removeAttribute("placeholder"),this.srcElement.classList.remove("treeselect-input--value-not-selected")):(l(this,y).setAttribute("placeholder",this.placeholder),this.srcElement.classList.add("treeselect-input--value-not-selected")),this.searchable?this.srcElement.classList.remove("treeselect-input--unsearchable"):this.srcElement.classList.add("treeselect-input--unsearchable"),this.isSingleSelect?this.srcElement.classList.add("treeselect-input--is-single-select"):this.srcElement.classList.remove("treeselect-input--is-single-select"),l(this,y).value=this.searchText},G=function(){this.isOpened=!this.isOpened,o(this,u,xe).call(this),this.isOpened?this.openCallback():this.closeCallback()},Lt=function({htmlTagsSection:e,htmlEditControl:t,htmlOperators:s}){let i=document.createElement("div");return i.classList.add("treeselect-input"),i.setAttribute("tabindex","-1"),i.addEventListener("mousedown",n=>o(this,u,Me).call(this,n)),i.addEventListener("focus",()=>this.focusCallback(),!0),i.addEventListener("blur",()=>this.blurCallback(),!0),e.appendChild(t),i.append(e,s),i},Me=function(e){e.stopPropagation(),this.isOpened||o(this,u,G).call(this),this.focus()},St=function(){let e=document.createElement("div");return e.classList.add("treeselect-input__tags"),e},Ne=function(){return this.value.map(e=>{let t=document.createElement("div");t.classList.add("treeselect-input__tags-element"),t.setAttribute("tabindex","-1"),t.setAttribute("tag-id",e.id.toString()),t.setAttribute("title",e.name);let s=o(this,u,He).call(this,e.name),i=o(this,u,Ae).call(this);return t.addEventListener("mousedown",n=>o(this,u,_e).call(this,n,e.id)),t.append(s,i),t})},_e=function(e,t){e.preventDefault(),e.stopPropagation(),this.removeItem(t),this.focus()},He=function(e){let t=document.createElement("span");return t.classList.add("treeselect-input__tags-name"),t.textContent=e,t},Ae=function(){let e=document.createElement("span");return e.classList.add("treeselect-input__tags-cross"),A(this.iconElements.cross,e),e},Oe=function(){let e=document.createElement("span");if(e.classList.add("treeselect-input__tags-count"),!this.value.length)return e.textContent="",e.setAttribute("title",""),e;let t=this.value.length===1?this.value[0].name:`${this.value.length} ${this.tagsCountText}`;return e.textContent=t,e.setAttribute("title",t),e},Tt=function(){let e=document.createElement("input");return e.classList.add("treeselect-input__edit"),this.id&&e.setAttribute("id",this.id),(!this.searchable||this.disabled)&&e.setAttribute("readonly","readonly"),this.disabled&&e.setAttribute("tabindex","-1"),this.ariaLabel.length&&e.setAttribute("aria-label",this.ariaLabel),e.addEventListener("keydown",t=>o(this,u,Ie).call(this,t)),e.addEventListener("input",t=>o(this,u,Be).call(this,t,e)),e},Ie=function(e){e.stopPropagation();let t=e.key;t==="Backspace"&&!this.searchText.length&&this.value.length&&!this.showTags&&this.clear(),t==="Backspace"&&!this.searchText.length&&this.value.length&&this.removeItem(this.value[this.value.length-1].id),e.code==="Space"&&(!this.searchText||!this.searchable)&&o(this,u,G).call(this),(t==="Enter"||t==="ArrowDown"||t==="ArrowUp")&&e.preventDefault(),this.keydownCallback(e),t!=="Tab"&&this.focus()},Be=function(e,t){e.stopPropagation();let s=this.searchText,i=t.value.trim();if(s.length===0&&i.length===0){t.value="";return}if(this.searchable){let n=e.target.value;this.searchCallback(n),this.isOpened||o(this,u,G).call(this)}else t.value="";this.searchText=t.value},yt=function(){let e=document.createElement("div");return e.classList.add("treeselect-input__operators"),e},Ve=function(){let e=document.createElement("span");return e.classList.add("treeselect-input__clear"),e.setAttribute("tabindex","-1"),A(this.iconElements.clear,e),e.addEventListener("mousedown",t=>o(this,u,Pe).call(this,t)),e},Pe=function(e){e.preventDefault(),e.stopPropagation(),(this.searchText.length||this.value.length)&&this.clear(),this.focus()},Ge=function(e){E(this,T,document.createElement("span")),l(this,T).classList.add("treeselect-input__arrow");let t=e?this.iconElements.arrowUp:this.iconElements.arrowDown;return A(t,l(this,T)),l(this,T).addEventListener("mousedown",s=>o(this,u,We).call(this,s)),l(this,T)},We=function(e){e.stopPropagation(),e.preventDefault(),this.focus(),o(this,u,G).call(this)},re=function(){this.inputCallback(this.value)};var xt=({newValue:e,optionsTreeMap:t,isSingleSelect:s,isIndependentNodes:i})=>{ns(t);let n=e.map(r=>t.get(r)??null).filter(r=>r!==null&&!r.disabled),[c]=n;if(s&&n.length&&c){c.checked=!0;return}n.forEach(r=>{r.checked=!0;let v=Ce({option:r,optionsTreeMap:t,isIndependentNodes:i});r.checked=v})},Ce=({option:{id:e,checked:t},optionsTreeMap:s,isIndependentNodes:i})=>{let n=s.get(e)??null;if(n===null)return!1;if(i)return n.checked=!n.disabled&&t,n.checked;let c=Mt({checked:t,currentOption:n,optionsTreeMap:s});return Nt({childOption:n,optionsTreeMap:s}),c},Mt=({checked:e,currentOption:t,optionsTreeMap:s})=>{if(!t.isGroup)return t.checked=!t.disabled&&e,t.isPartialChecked=!1,t.checked;let i=K({id:t.id,optionsTreeMap:s});return!e||t.disabled||t.isPartialChecked?(t.checked=!1,t.isPartialChecked=!1,ue({option:t,children:i,optionsTreeMap:s}),t.checked):_t({children:i,optionsTreeMap:s})?Ht(i)?(t.checked=!1,t.isPartialChecked=!1,t.disabled=!0,t.checked):(t.checked=!1,t.isPartialChecked=!0,i.forEach(n=>{Mt({checked:e,currentOption:n,optionsTreeMap:s})}),t.checked):(t.checked=!0,t.isPartialChecked=!1,ue({option:t,children:i,optionsTreeMap:s}),t.checked)},Nt=({childOption:e,optionsTreeMap:t})=>{let s=t.get(e.childOf)??null;s!==null&&(ss({parentOption:s,optionsTreeMap:t}),Nt({childOption:s,optionsTreeMap:t}))},ss=({parentOption:e,optionsTreeMap:t})=>{let s=K({id:e.id,optionsTreeMap:t});if(Ht(s)){e.checked=!1,e.isPartialChecked=!1,e.disabled=!0;return}if(is(s)){e.checked=!0,e.isPartialChecked=!1;return}if(ls(s)){e.checked=!1,e.isPartialChecked=!0;return}e.checked=!1,e.isPartialChecked=!1},ue=({option:{checked:e,disabled:t},children:s,optionsTreeMap:i})=>{s.forEach(n=>{n.disabled=t||n.disabled,n.checked=e&&!n.disabled,n.isPartialChecked=!1;let c=K({id:n.id,optionsTreeMap:i});ue({option:{checked:e,disabled:t},children:c,optionsTreeMap:i})})},_t=({children:e,optionsTreeMap:t})=>e.some(s=>s.disabled)?!0:e.some(s=>{if(!s.isGroup)return!1;let i=K({id:s.id,optionsTreeMap:t});return _t({children:i,optionsTreeMap:t})}),Ht=e=>e.every(t=>!!t.disabled),is=e=>e.every(t=>t.checked),ls=e=>e.some(t=>t.checked||t.isPartialChecked),ns=e=>{e.forEach(t=>{t.checked=!1,t.isPartialChecked=!1})},os=({options:e,openLevel:t,isIndependentNodes:s})=>{let i={level:0,groupId:""},n=new Map;return At({optionsTreeMap:n,options:e,openLevel:t,groupId:i.groupId,level:i.level}),hs({optionsTreeMap:n,isIndependentNodes:s}),n},At=({optionsTreeMap:e,options:t,openLevel:s,groupId:i,level:n})=>{t.forEach(c=>{var r,v;let g=(((r=c.children)==null?void 0:r.length)??0)>0,w=n>=s&&g,C=n>s,b=((v=c.children)==null?void 0:v.map(L=>L.value))??[],f=c.value;e.has(f)&&console.error(`Validation: You have duplicated option value: ${f}! You should use unique values. Duplicates will lead to unexpected behavior.`),e.set(f,{id:f,name:c.name,childOf:i,isGroup:g,checked:!1,isPartialChecked:!1,level:n,isClosed:w,hidden:C,disabled:c.disabled??!1,isGroupSelectable:!g||(c.isGroupSelectable??!0),children:b,checkboxHtmlElement:null,itemHtmlElement:null,arrowItemHtmlElement:null,checkboxIconHtmlElement:null}),g&&At({optionsTreeMap:e,options:c.children,openLevel:s,groupId:f,level:n+1})})},as=(e,t)=>e===null?null:t.get(e)??t.get(parseInt(e))??null,K=({id:e,optionsTreeMap:t})=>{let s=t.get(e)??null;return s===null?[]:s.children.reduce((i,n)=>{let c=t.get(n)??null;return c!==null&&i.push(c),i},[])},cs=e=>{let t=[],s=[],i=[];e.forEach(c=>{c.checked&&(i.push(c),c.isGroup?s.push(c):t.push(c))});let n=i.filter(c=>!s.some(({id:r})=>r===c.childOf));return{ungroupedNodes:t,groupedNodes:n,allNodes:i}},hs=({optionsTreeMap:e,isIndependentNodes:t})=>{let s=[];e.forEach(i=>{i.disabled&&s.push(i)}),s.forEach(({id:i})=>Ce({option:{id:i,checked:!1},optionsTreeMap:e,isIndependentNodes:t}))},X=(e,{id:t,isClosed:s})=>{K({id:t,optionsTreeMap:e}).forEach(i=>{i.hidden=s??!1,i.isGroup&&!i.isClosed&&X(e,{id:i.id,isClosed:s})})},rs=(e,t)=>{if(t){ds(e);return}e.forEach(s=>{s.checked&&we(s.childOf,e),s.isGroup&&!s.disabled&&(s.checked||s.isPartialChecked)&&(s.isClosed=!1,X(e,s))})},ds=e=>{let t=null;for(let[s,i]of e)if(i.checked&&!i.disabled){t=i;break}t&&(t.isGroup&&(t.isClosed=!1,X(e,t)),we(t.childOf,e))},we=(e,t)=>{let s=t.get(e)??null;s&&(s.isClosed=!1,X(t,s),we(s.childOf,t))},us=(e,t)=>{e.forEach(s=>{let i=s.name.toLowerCase().includes(t.toLowerCase());i&&(s.isGroup&&(s.isClosed=!0),s.childOf&&Ot(s.childOf,e)),s.hidden=!i})},Ot=(e,t)=>{let s=t.get(e)??null;s&&(s.hidden=!1,s.isClosed=!1,Ot(s.childOf,t))},ps=({optionsTreeMap:e,beforeSearchStateMap:t})=>{e.forEach(s=>{let i=t.get(s.id);i&&(s.hidden=i.hidden,s.isClosed=i.isClosed)}),t.clear()},ms=({optionsTreeMap:e,beforeSearchStateMap:t})=>{t.clear(),e.forEach(s=>{t.set(s.id,{hidden:s.hidden,isClosed:s.isClosed})})},vs=e=>new IntersectionObserver(t=>{t.forEach(s=>{s.target.classList.toggle("treeselect-list__item--scroll-not-visible",!s.isIntersecting)})},{root:e,threshold:.5}),bs=({optionsTreeMap:e,emptyListHtmlElement:t,iconElements:s,previousSingleSelectedValue:i,rtl:n})=>{e.forEach(c=>{let r=c.checkboxHtmlElement;r&&(r.checked=c.checked),Es({option:c,previousSingleSelectedValue:i}),Cs(c),ws(c),Ls({option:c,iconElements:s}),Ss(c),gs({option:c,optionsTreeMap:e,rtl:n}),Ts({option:c,iconElements:s}),ys(c)}),fs({optionsTreeMap:e,emptyListHtmlElement:t})},gs=({option:e,optionsTreeMap:t,rtl:s})=>{let i=e.level===0,n=20,c=5,r="0";if(i){let g=!1;for(let[C,b]of t)if(b.isGroup&&b.level===e.level){g=!0;break}let w=!e.isGroup&&g?`${n}px`:`${c}px`;r=e.isGroup?"0":w}else r=e.isGroup?`${e.level*n}px`:`${e.level*n+n}px`;let v=e.itemHtmlElement;v&&(s?v.style.paddingRight=r:v.style.paddingLeft=r,v.setAttribute("level",e.level.toString()),v.setAttribute("group",e.isGroup.toString()))},fs=({optionsTreeMap:e,emptyListHtmlElement:t})=>{let s=!1;for(let[i,n]of e)if(!n.hidden){s=!0;break}t?.classList.toggle("treeselect-list__empty--hidden",s)},ks=(e,t)=>{t&&Object.keys(t).forEach(s=>{let i=t[s];typeof i=="string"&&e.setAttribute(s,i)})},Es=({option:e,previousSingleSelectedValue:t})=>{let s=e.itemHtmlElement;s?.classList.toggle("treeselect-list__item--checked",e.checked);let i=Array.isArray(t)&&t[0]===e.id&&!e.disabled;s?.classList.toggle("treeselect-list__item--single-selected",i)},Cs=e=>{let t=e.itemHtmlElement;t?.classList.toggle("treeselect-list__item--partial-checked",e.isPartialChecked)},ws=e=>{let t=e.itemHtmlElement;t?.classList.toggle("treeselect-list__item--disabled",e.disabled)},Ls=({option:e,iconElements:t})=>{let s=e.arrowItemHtmlElement;if(e.isGroup&&s){let i=e.isClosed?t.arrowRight:t.arrowDown;A(i,s);let n=e.itemHtmlElement;n?.classList.toggle("treeselect-list__item--closed",e.isClosed)}},Ss=e=>{let t=e.itemHtmlElement;t?.classList.toggle("treeselect-list__item--hidden",e.hidden)},Ts=({option:e,iconElements:t})=>{let s=e.checkboxIconHtmlElement;s&&(e.checked?A(t.check,s):e.isPartialChecked?A(t.partialCheck,s):s.innerHTML="")},ys=e=>{let t=e.itemHtmlElement;t?.classList.toggle("treeselect-list__item--non-selectable-group",!e.isGroupSelectable)},xs=({newValue:e,optionsTreeMap:t,isSingleSelect:s,expandSelected:i,isFirstValueUpdate:n,isIndependentNodes:c})=>{xt({newValue:e,optionsTreeMap:t,isSingleSelect:s,isIndependentNodes:c}),n&&i&&rs(t,s)},D,W,R,Q,h,Y,It,Bt,Vt,De,Re,$e,le,Fe,je,Ue,ne,qe,ze,Ye,Ke,Xe,Je,Ze,Qe,et,pe,tt,st,oe,J,me,it,ve=class{constructor({options:t,value:s,openLevel:i,listSlotHtmlComponent:n,tagsSortFn:c,emptyText:r,isSingleSelect:v,iconElements:g,showCount:w,disabledBranchNode:C,expandSelected:b,isIndependentNodes:f,rtl:L,listClassName:x,isBoostedRendering:M,inputCallback:O,arrowClickCallback:V,mouseupCallback:I}){k(this,h),a(this,"options"),a(this,"value"),a(this,"openLevel"),a(this,"listSlotHtmlComponent"),a(this,"tagsSortFn"),a(this,"emptyText"),a(this,"isSingleSelect"),a(this,"showCount"),a(this,"disabledBranchNode"),a(this,"expandSelected"),a(this,"isIndependentNodes"),a(this,"rtl"),a(this,"listClassName"),a(this,"isBoostedRendering"),a(this,"iconElements"),a(this,"searchText"),a(this,"intersectionItemsObserver"),a(this,"selectedNodes"),a(this,"optionsTreeMap"),a(this,"beforeSearchStateMap"),a(this,"emptyListHtmlElement"),a(this,"srcElement"),a(this,"inputCallback"),a(this,"arrowClickCallback"),a(this,"mouseupCallback"),k(this,D,null),k(this,W,!0),k(this,R,[]),k(this,Q,!0),this.options=t,this.value=s,this.openLevel=i??0,this.listSlotHtmlComponent=n??null,this.tagsSortFn=c??null,this.emptyText=r??"No results found...",this.isSingleSelect=v??!1,this.showCount=w??!1,this.disabledBranchNode=C??!1,this.expandSelected=b??!1,this.isIndependentNodes=f??!1,this.rtl=L??!1,this.listClassName=x??"",this.isBoostedRendering=M,this.iconElements=g,this.searchText="",this.intersectionItemsObserver=null,this.selectedNodes={nodes:[],groupedNodes:[],allNodes:[]},this.optionsTreeMap=os({options:this.options,openLevel:this.openLevel,isIndependentNodes:this.isIndependentNodes}),this.beforeSearchStateMap=new Map,this.emptyListHtmlElement=null,this.srcElement=o(this,h,Vt).call(this),this.inputCallback=O,this.arrowClickCallback=V,this.mouseupCallback=I}updateValue(t){this.value=t,E(this,R,this.isSingleSelect?this.value:[]),xs({newValue:t,optionsTreeMap:this.optionsTreeMap,isSingleSelect:this.isSingleSelect,expandSelected:this.expandSelected,isFirstValueUpdate:l(this,Q),isIndependentNodes:this.isIndependentNodes}),o(this,h,Y).call(this),E(this,Q,!1),o(this,h,me).call(this)}updateSearchValue(t){if(t===this.searchText)return;let s=this.searchText===""&&t!=="";this.searchText=t,s&&ms({beforeSearchStateMap:this.beforeSearchStateMap,optionsTreeMap:this.optionsTreeMap}),this.searchText===""&&ps({beforeSearchStateMap:this.beforeSearchStateMap,optionsTreeMap:this.optionsTreeMap}),this.searchText&&us(this.optionsTreeMap,t),o(this,h,Y).call(this),this.focusFirstListElement()}callKeyAction(t){E(this,W,!1);let s=this.srcElement.querySelector(".treeselect-list__item--focused");if(s?.classList.contains("treeselect-list__item--hidden"))return;let i=t.key;i==="Enter"&&s&&s.dispatchEvent(new Event("mousedown")),(i==="ArrowLeft"||i==="ArrowRight")&&o(this,h,It).call(this,s,t),(i==="ArrowDown"||i==="ArrowUp")&&o(this,h,Bt).call(this,s,i)}focusFirstListElement(){let t="treeselect-list__item--focused",s=this.srcElement.querySelector(`.${t}`),i=o(this,h,pe).call(this);if(!i.length)return;s&&s.classList.remove(t);let[n]=i;n.classList.add(t)}isLastFocusedElementExist(){return!!l(this,D)}destroy(){this.intersectionItemsObserver&&this.intersectionItemsObserver.disconnect()}};D=new WeakMap,W=new WeakMap,R=new WeakMap,Q=new WeakMap,h=new WeakSet,Y=function(){bs({optionsTreeMap:this.optionsTreeMap,emptyListHtmlElement:this.emptyListHtmlElement,iconElements:this.iconElements,previousSingleSelectedValue:l(this,R),rtl:this.rtl})},It=function(e,t){if(!e)return;let s=t.key,i=e.querySelector(".treeselect-list__item-checkbox").getAttribute("input-id"),n=as(i,this.optionsTreeMap),c=n.arrowItemHtmlElement;s==="ArrowLeft"&&!n.isClosed&&n.isGroup&&(c.dispatchEvent(new Event("mousedown")),t.preventDefault()),s==="ArrowRight"&&n.isClosed&&n.isGroup&&(c.dispatchEvent(new Event("mousedown")),t.preventDefault())},Bt=function(e,t){var s;let i=o(this,h,pe).call(this);if(!i.length)return;let n="treeselect-list__item--focused";if(e){let c=i.findIndex(L=>L.classList.contains(n));i[c].classList.remove(n);let r=t==="ArrowDown"?c+1:c-1,v=t==="ArrowDown"?0:i.length-1,g=!i[r],w=i[r]??i[v];w.classList.add(n);let C=this.srcElement.getBoundingClientRect(),b=w.getBoundingClientRect();if(g&&t==="ArrowDown"){this.srcElement.scroll(0,0);return}if(g&&t==="ArrowUp"){this.srcElement.scroll(0,this.srcElement.scrollHeight);return}let f=((s=this.listSlotHtmlComponent)==null?void 0:s.clientHeight)??0;if(C.y+C.heightb.y){this.srcElement.scroll(0,this.srcElement.scrollTop-b.height);return}}else{let[c]=i;c.classList.add(n)}},Vt=function(){let e=o(this,h,De).call(this),t=o(this,h,le).call(this,this.options);e.append(...t);let s=o(this,h,je).call(this);e.append(s);let i=o(this,h,Fe).call(this);return i&&e.append(i),e},De=function(){let e=document.createElement("div");return e.classList.add("treeselect-list"),this.listClassName.length>0&&e.classList.add(this.listClassName),this.isSingleSelect&&e.classList.add("treeselect-list--single-select"),this.disabledBranchNode&&e.classList.add("treeselect-list--disabled-branch-node"),e.addEventListener("mouseout",t=>o(this,h,Re).call(this,t)),e.addEventListener("mousemove",()=>o(this,h,$e).call(this)),e.addEventListener("mouseup",()=>this.mouseupCallback(),!0),this.isBoostedRendering&&(this.intersectionItemsObserver=vs(e)),e},Re=function(e){e.stopPropagation(),l(this,D)&&l(this,W)&&l(this,D).classList.add("treeselect-list__item--focused")},$e=function(){E(this,W,!0)},le=function(e){return e.reduce((t,s)=>{var i;if((i=s.children)!=null&&i.length){let c=o(this,h,Ue).call(this,s),r=o(this,h,le).call(this,s.children);return c.append(...r),t.push(c),t}let n=o(this,h,ne).call(this,s,!1);return t.push(n),t},[])},Fe=function(){if(!this.listSlotHtmlComponent)return null;let e=document.createElement("div");return e.classList.add("treeselect-list__slot"),e.appendChild(this.listSlotHtmlComponent),e},je=function(){let e=document.createElement("div");e.classList.add("treeselect-list__empty"),e.setAttribute("title",this.emptyText);let t=document.createElement("span");t.classList.add("treeselect-list__empty-icon"),A(this.iconElements.attention,t);let s=document.createElement("span");return s.classList.add("treeselect-list__empty-text"),s.textContent=this.emptyText,e.append(t,s),this.emptyListHtmlElement=e,e},Ue=function(e){let t=document.createElement("div");t.setAttribute("group-container-id",e.value.toString()),t.classList.add("treeselect-list__group-container");let s=o(this,h,ne).call(this,e,!0);return t.appendChild(s),t},ne=function(e,t){let s=o(this,h,qe).call(this,e);if(t){let c=o(this,h,Xe).call(this,e);s.appendChild(c),s.classList.add("treeselect-list__item--group")}let i=o(this,h,Ze).call(this,e),n=o(this,h,Qe).call(this,e,t);return s.append(i,n),s},qe=function(e){let t=document.createElement("div");t.setAttribute("tabindex","-1"),t.setAttribute("title",e.name),ks(t,e.htmlAttr),t.classList.add("treeselect-list__item"),t.addEventListener("mouseover",()=>o(this,h,ze).call(this,t),!0),t.addEventListener("mouseout",()=>o(this,h,Ye).call(this,t),!0),t.addEventListener("mousedown",i=>o(this,h,Ke).call(this,i,e)),this.intersectionItemsObserver&&this.intersectionItemsObserver.observe(t);let s=this.optionsTreeMap.get(e.value);return s&&(s.itemHtmlElement=t),t},ze=function(e){l(this,W)&&o(this,h,oe).call(this,!0,e)},Ye=function(e){l(this,W)&&(o(this,h,oe).call(this,!1,e),E(this,D,e))},Ke=function(e,t){e.preventDefault(),e.stopPropagation();let s=this.optionsTreeMap.get(t.value)??null;if(s!=null&&s.disabled)return;let i=s?.checkboxHtmlElement;i&&(i.checked=!i.checked,o(this,h,tt).call(this,i,t))},Xe=function(e){let t=document.createElement("span");t.setAttribute("tabindex","-1"),t.classList.add("treeselect-list__item-icon"),A(this.iconElements.arrowDown,t),t.addEventListener("mousedown",i=>o(this,h,Je).call(this,i,e));let s=this.optionsTreeMap.get(e.value);return s&&(s.arrowItemHtmlElement=t),t},Je=function(e,t){e.preventDefault(),e.stopPropagation(),o(this,h,st).call(this,t)},Ze=function(e){let t=document.createElement("div");t.classList.add("treeselect-list__item-checkbox-container");let s=document.createElement("span");s.classList.add("treeselect-list__item-checkbox-icon"),s.innerHTML="";let i=document.createElement("input");i.setAttribute("tabindex","-1"),i.setAttribute("type","checkbox"),i.setAttribute("input-id",e.value.toString()),i.classList.add("treeselect-list__item-checkbox"),t.append(s,i);let n=this.optionsTreeMap.get(e.value);return n&&(n.checkboxHtmlElement=i,n.checkboxIconHtmlElement=s),t},Qe=function(e,t){let s=document.createElement("label");if(s.textContent=e.name,s.classList.add("treeselect-list__item-label"),t&&this.showCount){let i=o(this,h,et).call(this,e);s.appendChild(i)}return s},et=function(e){var t;let s=document.createElement("span"),i=((t=this.optionsTreeMap.get(e.value))==null?void 0:t.children)??[];return s.textContent=`(${i.length})`,s.classList.add("treeselect-list__item-label-counter"),s},pe=function(){let e=[];return this.optionsTreeMap.forEach(t=>{!t.hidden&&t.itemHtmlElement&&e.push(t.itemHtmlElement)}),e},tt=function(e,t){let s=this.optionsTreeMap.get(t.value)??null;if(s===null)return;let i=s.isGroupSelectable??!0;if(s.isGroup&&(this.disabledBranchNode||!i)){let n=s.arrowItemHtmlElement;n?.dispatchEvent(new Event("mousedown"));return}if(this.isSingleSelect){let[n]=l(this,R);if(s.id===n)return;E(this,R,[s.id]),xt({newValue:[s.id],optionsTreeMap:this.optionsTreeMap,isSingleSelect:this.isSingleSelect,isIndependentNodes:this.isIndependentNodes})}else{s.checked=e.checked;let n=Ce({option:s,optionsTreeMap:this.optionsTreeMap,isIndependentNodes:this.isIndependentNodes});e.checked=n}o(this,h,Y).call(this),o(this,h,it).call(this)},st=function(e){let t=this.optionsTreeMap.get(e.value)??null;t!==null&&(t.isClosed=!t.isClosed,X(this.optionsTreeMap,t),o(this,h,Y).call(this),this.arrowClickCallback(t.id,t.isClosed))},oe=function(e,t){let s="treeselect-list__item--focused";if(e){let i=Array.from(this.srcElement.querySelectorAll(`.${s}`));i.length&&i.forEach(n=>n.classList.remove(s)),t.classList.add(s)}else t.classList.remove(s)},J=function(e){return this.tagsSortFn===null?e:[...e].sort((t,s)=>this.tagsSortFn({value:t.id,name:t.name},{value:s.id,name:s.name}))},me=function(){let{ungroupedNodes:e,groupedNodes:t,allNodes:s}=cs(this.optionsTreeMap);this.selectedNodes={nodes:o(this,h,J).call(this,e),groupedNodes:o(this,h,J).call(this,t),allNodes:o(this,h,J).call(this,s)}},it=function(){o(this,h,me).call(this),this.inputCallback(this.selectedNodes),this.value=this.selectedNodes.nodes.map(e=>e.id)};var lt=({parentHtmlContainer:e,staticList:t,appendToBody:s,isSingleSelect:i,value:n,direction:c})=>{e||console.error("Validation: parentHtmlContainer prop is required!"),t&&s&&console.error("Validation: You should set staticList to false if you use appendToBody!"),i&&Array.isArray(n)&&console.error("Validation: if you use isSingleSelect prop, you should pass a single value!"),!i&&!Array.isArray(n)&&console.error("Validation: you should pass an array as a value!"),c&&c!=="auto"&&c!=="bottom"&&c!=="top"&&console.error("Validation: you should pass (auto | top | bottom | undefined) as a value for the direction prop!")},Z=e=>e.map(t=>t.id),Ms=e=>e==null?[]:Array.isArray(e)?e:[e],Ns=(e,t)=>{if(t){let[s]=e;return s??null}return e},p,m,j,ee,U,_,H,S,P,d,be,ae,nt,ot,at,ct,ht,rt,ge,dt,ut,pt,mt,fe,ke,se,ce,te,vt,he,bt,gt,ft,kt,Et,ie=class{constructor({parentHtmlContainer:t,value:s,options:i,openLevel:n,appendToBody:c,alwaysOpen:r,showTags:v,tagsCountText:g,tagsSortFn:w,clearable:C,searchable:b,placeholder:f,grouped:L,isGroupedValue:x,listSlotHtmlComponent:M,disabled:O,emptyText:V,staticList:I,id:N,ariaLabel:F,isSingleSelect:Le,showCount:Pt,disabledBranchNode:Gt,direction:Wt,expandSelected:Dt,saveScrollPosition:Rt,isIndependentNodes:$t,rtl:Ft,listClassName:jt,isBoostedRendering:Ut,iconElements:qt,inputCallback:zt,openCallback:Yt,closeCallback:Kt,nameChangeCallback:Xt,searchCallback:Jt,openCloseGroupCallback:Zt}){k(this,d),a(this,"parentHtmlContainer"),a(this,"value"),a(this,"options"),a(this,"openLevel"),a(this,"appendToBody"),a(this,"alwaysOpen"),a(this,"showTags"),a(this,"tagsCountText"),a(this,"tagsSortFn"),a(this,"clearable"),a(this,"searchable"),a(this,"placeholder"),a(this,"grouped"),a(this,"isGroupedValue"),a(this,"listSlotHtmlComponent"),a(this,"disabled"),a(this,"emptyText"),a(this,"staticList"),a(this,"id"),a(this,"ariaLabel"),a(this,"isSingleSelect"),a(this,"showCount"),a(this,"disabledBranchNode"),a(this,"direction"),a(this,"expandSelected"),a(this,"saveScrollPosition"),a(this,"isIndependentNodes"),a(this,"rtl"),a(this,"listClassName"),a(this,"isBoostedRendering"),a(this,"iconElements"),a(this,"inputCallback"),a(this,"openCallback"),a(this,"closeCallback"),a(this,"nameChangeCallback"),a(this,"searchCallback"),a(this,"openCloseGroupCallback"),a(this,"ungroupedValue"),a(this,"groupedValue"),a(this,"allValue"),a(this,"isListOpened"),a(this,"selectedName"),a(this,"srcElement"),k(this,p,null),k(this,m,null),k(this,j,null),k(this,ee,0),k(this,U,0),k(this,_,null),k(this,H,null),k(this,S,null),k(this,P,null),lt({parentHtmlContainer:t,value:s,staticList:I,appendToBody:c,isSingleSelect:Le}),this.parentHtmlContainer=t,this.value=[],this.options=i??[],this.openLevel=n??0,this.appendToBody=c??!1,this.alwaysOpen=!!(r&&!O),this.showTags=v??!0,this.tagsCountText=g??"elements selected",this.tagsSortFn=w??null,this.clearable=C??!0,this.searchable=b??!0,this.placeholder=f??"Search...",this.grouped=L??!0,this.isGroupedValue=x??!1,this.listSlotHtmlComponent=M??null,this.disabled=O??!1,this.emptyText=V??"No results found...",this.staticList=!!(I&&!this.appendToBody),this.id=N??"",this.ariaLabel=F??"",this.isSingleSelect=Le??!1,this.showCount=Pt??!1,this.disabledBranchNode=Gt??!1,this.direction=Wt??"auto",this.expandSelected=Dt??!1,this.saveScrollPosition=Rt??!0,this.isIndependentNodes=$t??!1,this.rtl=Ft??!1,this.listClassName=jt??"",this.isBoostedRendering=Ut??!1,this.iconElements=Te(qt),this.inputCallback=zt,this.openCallback=Yt,this.closeCallback=Kt,this.nameChangeCallback=Xt,this.searchCallback=Jt,this.openCloseGroupCallback=Zt,this.ungroupedValue=[],this.groupedValue=[],this.allValue=[],this.isListOpened=!1,this.selectedName="",this.srcElement=null,o(this,d,be).call(this,s)}mount(){lt({parentHtmlContainer:this.parentHtmlContainer,value:this.value,staticList:this.staticList,appendToBody:this.appendToBody,isSingleSelect:this.isSingleSelect}),this.iconElements=Te(this.iconElements),o(this,d,be).call(this,this.value)}updateValue(t){let s=Ms(t),i=l(this,p);i&&(i.updateValue(s),o(this,d,ge).call(this,i?.selectedNodes))}destroy(){var t;this.srcElement&&(o(this,d,fe).call(this),this.srcElement.innerHTML="",this.srcElement=null,o(this,d,te).call(this,!0),(t=l(this,p))==null||t.destroy())}focus(){l(this,m)&&l(this,m).focus()}toggleOpenClose(){l(this,m)&&(l(this,m).openClose(),l(this,m).focus())}scrollWindowHandler(){this.updateListPosition()}focusWindowHandler(t){var s,i,n;(s=this.srcElement)!=null&&s.contains(t.target)||(i=l(this,p))!=null&&i.srcElement.contains(t.target)||((n=l(this,m))==null||n.blur(),o(this,d,te).call(this,!1),o(this,d,se).call(this,!1))}blurWindowHandler(){var t;(t=l(this,m))==null||t.blur(),o(this,d,te).call(this,!1),o(this,d,se).call(this,!1)}updateListPosition(){var t;let s=this.srcElement,i=(t=l(this,p))==null?void 0:t.srcElement;if(!s||!i)return;if(this.staticList){i.setAttribute("direction","bottom"),o(this,d,ke).call(this,!1,this.appendToBody);return}let{height:n}=i.getBoundingClientRect(),{x:c,y:r,height:v,width:g}=s.getBoundingClientRect(),w=window.innerHeight,C=r,b=w-r-v,f=C>b&&C>=n&&bo(this,d,dt).call(this,i),arrowClickCallback:(i,n)=>o(this,d,ut).call(this,i,n),mouseupCallback:()=>{var i;return(i=l(this,m))==null?void 0:i.focus()}}),s=new de({value:[],showTags:this.showTags,tagsCountText:this.tagsCountText,clearable:this.clearable,isAlwaysOpened:this.alwaysOpen,searchable:this.searchable,placeholder:this.placeholder,disabled:this.disabled,isSingleSelect:this.isSingleSelect,id:this.id,ariaLabel:this.ariaLabel,iconElements:this.iconElements,inputCallback:i=>o(this,d,ot).call(this,i),searchCallback:i=>o(this,d,ct).call(this,i),openCallback:()=>o(this,d,mt).call(this),closeCallback:()=>o(this,d,fe).call(this),keydownCallback:i=>o(this,d,at).call(this,i),focusCallback:()=>o(this,d,ht).call(this),blurCallback:()=>o(this,d,rt).call(this),nameChangeCallback:i=>o(this,d,pt).call(this,i)});return this.rtl&&(e.setAttribute("dir","rtl"),t.srcElement.setAttribute("dir","rtl")),this.appendToBody&&E(this,j,new ResizeObserver(()=>this.updateListPosition())),e.append(s.srcElement),{container:e,list:t,input:s}},ot=function(e){var t,s;let i=Z(e);(t=l(this,p))==null||t.updateValue(i);let n=((s=l(this,p))==null?void 0:s.selectedNodes)??{};o(this,d,ae).call(this,n),o(this,d,he).call(this)},at=function(e){var t;this.isListOpened&&((t=l(this,p))==null||t.callKeyAction(e))},ct=function(e){l(this,U)&&clearTimeout(l(this,U)),E(this,U,window.setTimeout(()=>{var t;(t=l(this,p))==null||t.updateSearchValue(e),this.updateListPosition()},350)),o(this,d,kt).call(this,e)},ht=function(){o(this,d,se).call(this,!0),l(this,S)&&l(this,S)&&l(this,P)&&(document.addEventListener("mousedown",l(this,S),!0),document.addEventListener("focus",l(this,S),!0),window.addEventListener("blur",l(this,P)))},rt=function(){setTimeout(()=>{var e,t;let s=(e=l(this,m))==null?void 0:e.srcElement.contains(document.activeElement),i=(t=l(this,p))==null?void 0:t.srcElement.contains(document.activeElement);!s&&!i&&this.blurWindowHandler()},1)},ge=function(e){var t;if(!e)return;let s=[];this.isIndependentNodes||this.isSingleSelect?s=e.allNodes:this.grouped?s=e.groupedNodes:s=e.nodes,(t=l(this,m))==null||t.updateValue(s),o(this,d,ae).call(this,e)},dt=function(e){var t,s,i;o(this,d,ge).call(this,e),this.isSingleSelect&&!this.alwaysOpen&&((t=l(this,m))==null||t.openClose(),(s=l(this,m))==null||s.clearSearch()),(i=l(this,m))==null||i.focus(),o(this,d,he).call(this)},ut=function(e,t){var s;(s=l(this,m))==null||s.focus(),this.updateListPosition(),o(this,d,Et).call(this,e,t)},pt=function(e){this.selectedName!==e&&(this.selectedName=e,o(this,d,bt).call(this))},mt=function(){var e;this.isListOpened=!0,l(this,_)&&l(this,H)&&(window.addEventListener("scroll",l(this,_),!0),window.addEventListener("resize",l(this,H))),!(!l(this,p)||!this.srcElement)&&(this.appendToBody?(document.body.appendChild(l(this,p).srcElement),(e=l(this,j))==null||e.observe(this.srcElement)):this.srcElement.appendChild(l(this,p).srcElement),this.updateListPosition(),o(this,d,ce).call(this,!0),o(this,d,vt).call(this),o(this,d,gt).call(this))},fe=function(){var e;this.alwaysOpen||(this.isListOpened=!1,l(this,_)&&l(this,H)&&(window.removeEventListener("scroll",l(this,_),!0),window.removeEventListener("resize",l(this,H))),!l(this,p)||!this.srcElement)||!(this.appendToBody?document.body.contains(l(this,p).srcElement):this.srcElement.contains(l(this,p).srcElement))||(E(this,ee,l(this,p).srcElement.scrollTop),this.appendToBody?(document.body.removeChild(l(this,p).srcElement),(e=l(this,j))==null||e.disconnect()):this.srcElement.removeChild(l(this,p).srcElement),o(this,d,ce).call(this,!1),o(this,d,ft).call(this))},ke=function(e,t){if(!l(this,p)||!l(this,m))return;let s=t?"treeselect-list--top-to-body":"treeselect-list--top",i=t?"treeselect-list--bottom-to-body":"treeselect-list--bottom";e?(l(this,p).srcElement.classList.add(s),l(this,p).srcElement.classList.remove(i),l(this,m).srcElement.classList.add("treeselect-input--top"),l(this,m).srcElement.classList.remove("treeselect-input--bottom")):(l(this,p).srcElement.classList.remove(s),l(this,p).srcElement.classList.add(i),l(this,m).srcElement.classList.remove("treeselect-input--top"),l(this,m).srcElement.classList.add("treeselect-input--bottom"))},se=function(e){!l(this,m)||!l(this,p)||(e?(l(this,m).srcElement.classList.add("treeselect-input--focused"),l(this,p).srcElement.classList.add("treeselect-list--focused")):(l(this,m).srcElement.classList.remove("treeselect-input--focused"),l(this,p).srcElement.classList.remove("treeselect-list--focused")))},ce=function(e){var t,s,i,n;e?(t=l(this,m))==null||t.srcElement.classList.add("treeselect-input--opened"):(s=l(this,m))==null||s.srcElement.classList.remove("treeselect-input--opened"),this.staticList?(i=l(this,p))==null||i.srcElement.classList.add("treeselect-list--static"):(n=l(this,p))==null||n.srcElement.classList.remove("treeselect-list--static")},te=function(e){!l(this,_)||!l(this,H)||!l(this,S)||!l(this,P)||((!this.alwaysOpen||e)&&(window.removeEventListener("scroll",l(this,_),!0),window.removeEventListener("resize",l(this,H))),document.removeEventListener("mousedown",l(this,S),!0),document.removeEventListener("focus",l(this,S),!0),window.removeEventListener("blur",l(this,P)))},vt=function(){var e,t,s;let i=(e=l(this,p))==null?void 0:e.isLastFocusedElementExist();this.saveScrollPosition&&i?(t=l(this,p))==null||t.srcElement.scroll(0,l(this,ee)):(s=l(this,p))==null||s.focusFirstListElement()},he=function(){var e;(e=this.srcElement)==null||e.dispatchEvent(new CustomEvent("input",{detail:this.value})),this.inputCallback&&this.inputCallback(this.value)},bt=function(){var e;(e=this.srcElement)==null||e.dispatchEvent(new CustomEvent("name-change",{detail:this.selectedName})),this.nameChangeCallback&&this.nameChangeCallback(this.selectedName)},gt=function(){var e;this.alwaysOpen||((e=this.srcElement)==null||e.dispatchEvent(new CustomEvent("open",{detail:this.value})),this.openCallback&&this.openCallback(this.value))},ft=function(){var e;this.alwaysOpen||((e=this.srcElement)==null||e.dispatchEvent(new CustomEvent("close",{detail:this.value})),this.closeCallback&&this.closeCallback(this.value))},kt=function(e){var t;let s=e?.trim()??"";(t=this.srcElement)==null||t.dispatchEvent(new CustomEvent("search",{detail:s})),this.searchCallback&&this.searchCallback(s)},Et=function(e,t){var s;(s=this.srcElement)==null||s.dispatchEvent(new CustomEvent("open-close-group",{detail:{groupId:e,isClosed:t}})),this.openCloseGroupCallback&&this.openCloseGroupCallback(e,t)};function _s({state:e,name:t,options:s,searchable:i,showCount:n,placeholder:c,rtl:r,disabledBranchNode:v=!0,disabled:g=!1,isSingleSelect:w=!0,showTags:C=!0,clearable:b=!0,isIndependentNodes:f=!0,alwaysOpen:L=!1,emptyText:x,expandSelected:M=!0,grouped:O=!0,openLevel:V=0,direction:I="auto"}){return{state:e,tree:null,formatState:function(N){return Array.isArray(N)?(N??[]).map(F=>F?.toString()):N?.toString()},init(){this.tree=new ie({id:`tree-${t}-id`,ariaLabel:`tree-${t}-label`,parentHtmlContainer:this.$refs.tree,value:this.formatState(this.state),options:s,searchable:i,showCount:n,placeholder:c,disabledBranchNode:v,disabled:g,isSingleSelect:w,showTags:C,clearable:b,isIndependentNodes:f,alwaysOpen:L,emptyText:x,expandSelected:M,grouped:O,openLevel:V,direction:I,rtl:r}),this.tree.srcElement.addEventListener("input",N=>{this.state=N.detail})}}}export{_s as default}; 2 | -------------------------------------------------------------------------------- /resources/images/example-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/fdb9dcccc9e800a741d663e3d3dc89d111db5ee0/resources/images/example-1.jpg -------------------------------------------------------------------------------- /resources/images/example-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/fdb9dcccc9e800a741d663e3d3dc89d111db5ee0/resources/images/example-2.jpg -------------------------------------------------------------------------------- /resources/images/example-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/fdb9dcccc9e800a741d663e3d3dc89d111db5ee0/resources/images/example-3.jpg -------------------------------------------------------------------------------- /resources/images/thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/fdb9dcccc9e800a741d663e3d3dc89d111db5ee0/resources/images/thumbnail.jpg -------------------------------------------------------------------------------- /resources/js/index.js: -------------------------------------------------------------------------------- 1 | import Treeselect from 'treeselectjs' 2 | 3 | export default function selectTree({ 4 | state, 5 | name, 6 | options, 7 | searchable, 8 | showCount, 9 | placeholder, 10 | rtl, 11 | disabledBranchNode = true, 12 | disabled = false, 13 | isSingleSelect = true, 14 | showTags = true, 15 | clearable = true, 16 | isIndependentNodes = true, 17 | alwaysOpen = false, 18 | emptyText, 19 | expandSelected = true, 20 | grouped = true, 21 | openLevel = 0, 22 | direction = 'auto' 23 | }) { 24 | return { 25 | state, 26 | 27 | /** @type Treeselect */ 28 | tree: null, 29 | 30 | formatState: function (state) { 31 | if (Array.isArray(state)) { 32 | return (state ?? []).map((item) => item?.toString()) 33 | } 34 | 35 | return state?.toString() 36 | }, 37 | 38 | 39 | init() { 40 | this.tree = new Treeselect({ 41 | id: `tree-${name}-id`, 42 | ariaLabel: `tree-${name}-label`, 43 | parentHtmlContainer: this.$refs.tree, 44 | value: this.formatState(this.state), 45 | options, 46 | searchable, 47 | showCount, 48 | placeholder, 49 | disabledBranchNode, 50 | disabled, 51 | isSingleSelect, 52 | showTags, 53 | clearable, 54 | isIndependentNodes, 55 | alwaysOpen, 56 | emptyText, 57 | expandSelected, 58 | grouped, 59 | openLevel, 60 | direction, 61 | rtl 62 | }); 63 | 64 | this.tree.srcElement.addEventListener('input', (e) => { 65 | this.state = e.detail; 66 | }); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /resources/lang/en/select-tree.php: -------------------------------------------------------------------------------- 1 | 14 |
current())) 18 | x-load="visible || event (ax-modal-opened)" 19 | @else 20 | x-load 21 | @endif 22 | x-load-css="[@js(FilamentAsset::getStyleHref('filament-select-tree-styles', package: 'codewithdennis/filament-select-tree'))]" 23 | x-load-src="{{ FilamentAsset::getAlpineComponentSrc('filament-select-tree', package: 'codewithdennis/filament-select-tree') }}" 24 | x-data="selectTree({ 25 | name: @js($getName()), 26 | state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$getStatePath()}')") }}, 27 | options: @js($getTree()), 28 | searchable: @js($isSearchable()), 29 | showCount: @js($getWithCount()), 30 | placeholder: @js($getPlaceholder()), 31 | disabledBranchNode: @js(!$getEnableBranchNode()), 32 | disabled: @js($isDisabled()), 33 | isSingleSelect: @js(!$getMultiple()), 34 | isIndependentNodes: @js($getIndependent()), 35 | showTags: @js($getMultiple()), 36 | alwaysOpen: @js($getAlwaysOpen()), 37 | clearable: @js($getClearable()), 38 | emptyText: @js($getEmptyLabel()), 39 | expandSelected: @js($getExpandSelected()), 40 | grouped: @js($getGrouped()), 41 | openLevel: @js($getDefaultOpenLevel()), 42 | direction: @js($getDirection()), 43 | rtl: @js(__('filament-panels::layout.direction') === 'rtl'), 44 | })" 45 | > 46 | 55 |
56 |
57 |
58 | 59 | -------------------------------------------------------------------------------- /src/FilamentSelectTreeServiceProvider.php: -------------------------------------------------------------------------------- 1 | name(static::$name) 18 | ->hasViews(); 19 | } 20 | 21 | public function packageBooted(): void 22 | { 23 | FilamentAsset::register([ 24 | AlpineComponent::make('filament-select-tree', __DIR__.'/../resources/dist/filament-select-tree.js'), 25 | Css::make('filament-select-tree-styles', __DIR__.'/../resources/dist/filament-select-tree.css'), 26 | ], 'codewithdennis/filament-select-tree'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/SelectTree.php: -------------------------------------------------------------------------------- 1 | loadStateFromRelationshipsUsing(static function (self $component): void { 97 | // Get the current relationship associated with the component. 98 | $relationship = $component->getRelationship(); 99 | 100 | // Check if the relationship is a BelongsToMany relationship. 101 | if ($relationship instanceof BelongsToMany) { 102 | // Retrieve related model instances and extract their IDs into an array. 103 | $state = $relationship->getResults() 104 | ->pluck($relationship->getRelatedKeyName()) 105 | ->toArray(); 106 | 107 | // Set the component's state with the extracted IDs. 108 | $component->state($state); 109 | } 110 | }); 111 | 112 | // Save relationships using a callback function. 113 | $this->saveRelationshipsUsing(static function (self $component, $state) { 114 | // Check if the component's relationship is a BelongsToMany relationship. 115 | if ($component->getRelationship() instanceof BelongsToMany) { 116 | // Wrap the state in a collection and convert it to an array if it's not set. 117 | $state = Arr::wrap($state ?? []); 118 | 119 | $pivotData = $component->getPivotData(); 120 | 121 | // Sync the relationship with the provided state (IDs). 122 | if ($pivotData === []) { 123 | $component->getRelationship()->sync($state ?? []); 124 | 125 | return; 126 | } 127 | 128 | // Sync the relationship with the provided state (IDs) plus pivot data. 129 | $component->getRelationship()->syncWithPivotValues($state ?? [], $pivotData); 130 | } 131 | }); 132 | 133 | $this->createOptionUsing(static function (SelectTree $component, array $data, Form $form) { 134 | $record = $component->getRelationship()->getRelated(); 135 | $record->fill($data); 136 | $record->save(); 137 | 138 | $form->model($record)->saveRelationships(); 139 | 140 | return $component->getCustomKey($record); 141 | }); 142 | 143 | $this->dehydrated(fn (SelectTree $component): bool => ! $component->getRelationship() instanceof BelongsToMany); 144 | 145 | $this->placeholder(static fn (SelectTree $component): ?string => $component->isDisabled() ? null : __('filament-forms::components.select.placeholder')); 146 | 147 | $this->suffixActions([ 148 | static fn (SelectTree $component): ?Action => $component->getCreateOptionAction(), 149 | ]); 150 | 151 | $this->treeKey('treeKey-'.rand()); 152 | } 153 | 154 | protected function buildTree(): Collection 155 | { 156 | // Start with two separate query builders 157 | $nullParentQuery = $this->getRelationship()->getRelated()->query()->where($this->getParentAttribute(), $this->getParentNullValue()); 158 | $nonNullParentQuery = $this->getRelationship()->getRelated()->query()->whereNot($this->getParentAttribute(), $this->getParentNullValue()); 159 | 160 | // If we're not at the root level and a modification callback is provided, apply it to null query 161 | if ($this->modifyQueryUsing) { 162 | $nullParentQuery = $this->evaluate($this->modifyQueryUsing, ['query' => $nullParentQuery]); 163 | } 164 | 165 | // If we're at the child level and a modification callback is provided, apply it to non null query 166 | if ($this->modifyChildQueryUsing) { 167 | $nonNullParentQuery = $this->evaluate($this->modifyChildQueryUsing, ['query' => $nonNullParentQuery]); 168 | } 169 | 170 | if ($this->withTrashed) { 171 | $nullParentQuery->withTrashed($this->withTrashed); 172 | $nonNullParentQuery->withTrashed($this->withTrashed); 173 | } 174 | 175 | $nullParentResults = $nullParentQuery->get(); 176 | $nonNullParentResults = $nonNullParentQuery->get(); 177 | 178 | // Combine the results from both queries 179 | $combinedResults = $nullParentResults->concat($nonNullParentResults); 180 | 181 | // Store results for additional functionality 182 | if ($this->storeResults) { 183 | $this->results = $combinedResults; 184 | } 185 | 186 | return $this->buildTreeFromResults($combinedResults); 187 | } 188 | 189 | private function buildTreeFromResults($results, $parent = null): Collection 190 | { 191 | // Assign the parent's null value to the $parent variable if it's not null 192 | if ($parent == null || $parent == $this->getParentNullValue()) { 193 | $parent = $this->getParentNullValue() ?? $parent; 194 | } 195 | 196 | // Create a collection to store the tree 197 | $tree = collect(); 198 | 199 | // Create a mapping of results by their parent IDs for faster lookup 200 | $resultMap = []; 201 | 202 | // Group results by their parent IDs 203 | foreach ($results as $result) { 204 | $parentId = $result->{$this->getParentAttribute()}; 205 | if (! isset($resultMap[$parentId])) { 206 | $resultMap[$parentId] = []; 207 | } 208 | $resultMap[$parentId][] = $result; 209 | } 210 | 211 | // Define disabled options 212 | $disabledOptions = $this->getDisabledOptions(); 213 | 214 | // Define hidden options 215 | $hiddenOptions = $this->getHiddenOptions(); 216 | 217 | // Recursively build the tree starting from the root (null parent) 218 | $rootResults = $resultMap[$parent] ?? []; 219 | foreach ($rootResults as $result) { 220 | // Build a node and add it to the tree 221 | $node = $this->buildNode($result, $resultMap, $disabledOptions, $hiddenOptions); 222 | $tree->push($node); 223 | } 224 | 225 | return $tree; 226 | } 227 | 228 | private function buildNode($result, $resultMap, $disabledOptions, $hiddenOptions): array 229 | { 230 | $key = $this->getCustomKey($result); 231 | 232 | // Create a node with 'name' and 'value' attributes 233 | $node = [ 234 | 'name' => $result->{$this->getTitleAttribute()}, 235 | 'value' => $key, 236 | 'parent' => (string) $result->{$this->getParentAttribute()}, 237 | 'disabled' => in_array($key, $disabledOptions), 238 | 'hidden' => in_array($key, $hiddenOptions), 239 | ]; 240 | 241 | // Check if the result has children 242 | if (isset($resultMap[$key])) { 243 | $children = collect(); 244 | // Recursively build child nodes 245 | foreach ($resultMap[$key] as $child) { 246 | // don't add the hidden ones 247 | if (in_array($this->getCustomKey($child), $hiddenOptions)) { 248 | continue; 249 | } 250 | $childNode = $this->buildNode($child, $resultMap, $disabledOptions, $hiddenOptions); 251 | $children->push($childNode); 252 | } 253 | // Add children to the node 254 | $node['children'] = $children->toArray(); 255 | } 256 | 257 | return $node; 258 | } 259 | 260 | public function relationship(string $relationship, string $titleAttribute, string $parentAttribute, ?Closure $modifyQueryUsing = null, ?Closure $modifyChildQueryUsing = null): self 261 | { 262 | $this->relationship = $relationship; 263 | $this->titleAttribute = $titleAttribute; 264 | $this->parentAttribute = $parentAttribute; 265 | $this->modifyQueryUsing = $modifyQueryUsing; 266 | $this->modifyChildQueryUsing = $modifyChildQueryUsing; 267 | 268 | return $this; 269 | } 270 | 271 | public function withCount(bool $withCount = true): static 272 | { 273 | $this->withCount = $withCount; 274 | 275 | return $this; 276 | } 277 | 278 | public function withTrashed(bool $withTrashed = true): static 279 | { 280 | $this->withTrashed = $withTrashed; 281 | 282 | return $this; 283 | } 284 | 285 | public function direction(string $direction): static 286 | { 287 | $this->direction = $direction; 288 | 289 | return $this; 290 | } 291 | 292 | public function parentNullValue(int|string|null $parentNullValue = null): static 293 | { 294 | $this->parentNullValue = $parentNullValue; 295 | 296 | return $this; 297 | } 298 | 299 | public function multiple(Closure|bool $multiple = true): static 300 | { 301 | $this->multiple = $multiple; 302 | 303 | return $this; 304 | } 305 | 306 | public function prepend(Closure|array|null $prepend = null): static 307 | { 308 | $this->prepend = $this->evaluate($prepend); 309 | 310 | if (is_array($this->prepend) && isset($this->prepend['name'], $this->prepend['value'])) { 311 | $this->prepend['value'] = (string) $this->prepend['value']; 312 | } else { 313 | throw new \InvalidArgumentException('The provided prepend value must be an array with "name" and "value" keys.'); 314 | } 315 | 316 | return $this; 317 | } 318 | 319 | public function getRelationship(): BelongsToMany|BelongsTo 320 | { 321 | return $this->getModelInstance()->{$this->evaluate($this->relationship)}(); 322 | } 323 | 324 | public function getTitleAttribute(): string 325 | { 326 | return $this->evaluate($this->titleAttribute); 327 | } 328 | 329 | public function getParentAttribute(): string 330 | { 331 | return $this->evaluate($this->parentAttribute); 332 | } 333 | 334 | public function getParentNullValue(): null|int|string 335 | { 336 | return $this->evaluate($this->parentNullValue); 337 | } 338 | 339 | public function clearable(bool $clearable = true): static 340 | { 341 | $this->clearable = $clearable; 342 | 343 | return $this; 344 | } 345 | 346 | public function grouped(bool $grouped = true): static 347 | { 348 | $this->grouped = $grouped; 349 | 350 | return $this; 351 | } 352 | 353 | public function defaultOpenLevel(Closure|int $defaultOpenLevel = 0): static 354 | { 355 | $this->defaultOpenLevel = $defaultOpenLevel; 356 | 357 | return $this; 358 | } 359 | 360 | public function expandSelected(bool $expandSelected = true): static 361 | { 362 | $this->expandSelected = $expandSelected; 363 | 364 | return $this; 365 | } 366 | 367 | public function emptyLabel(string $emptyLabel): static 368 | { 369 | $this->noSearchResultsMessage($emptyLabel); 370 | 371 | return $this; 372 | } 373 | 374 | public function independent(bool $independent = true): static 375 | { 376 | $this->independent = $independent; 377 | 378 | return $this; 379 | } 380 | 381 | public function withKey(string $customKey): static 382 | { 383 | $this->customKey = $customKey; 384 | 385 | return $this; 386 | } 387 | 388 | public function disabledOptions(Closure|array $disabledOptions): static 389 | { 390 | $this->disabledOptions = $disabledOptions; 391 | 392 | return $this; 393 | } 394 | 395 | public function hiddenOptions(Closure|array $hiddenOptions): static 396 | { 397 | $this->hiddenOptions = $hiddenOptions; 398 | 399 | return $this; 400 | } 401 | 402 | public function alwaysOpen(bool $alwaysOpen = true): static 403 | { 404 | $this->alwaysOpen = $alwaysOpen; 405 | 406 | return $this; 407 | } 408 | 409 | public function enableBranchNode(bool $enableBranchNode = true): static 410 | { 411 | $this->enableBranchNode = $enableBranchNode; 412 | 413 | return $this; 414 | } 415 | 416 | public function storeResults(bool $storeResults = true): static 417 | { 418 | $this->storeResults = $storeResults; 419 | 420 | return $this; 421 | } 422 | 423 | public function getTree(): Collection|array 424 | { 425 | return $this->evaluate($this->buildTree()->when($this->prepend, 426 | fn (Collection $tree) => $tree->prepend($this->evaluate($this->prepend)))); 427 | } 428 | 429 | public function getResults(): Collection|array|null 430 | { 431 | return $this->evaluate($this->results); 432 | } 433 | 434 | public function getExpandSelected(): bool 435 | { 436 | return $this->evaluate($this->expandSelected); 437 | } 438 | 439 | public function getGrouped(): bool 440 | { 441 | return $this->evaluate($this->grouped); 442 | } 443 | 444 | public function getWithTrashed(): bool 445 | { 446 | return $this->evaluate($this->withTrashed); 447 | } 448 | 449 | public function getIndependent(): bool 450 | { 451 | return $this->evaluate($this->independent); 452 | } 453 | 454 | public function getCustomKey($record): string 455 | { 456 | $key = is_null($this->customKey) ? $record->getKey() : $record->{$this->customKey}; 457 | 458 | return (string) $key; 459 | } 460 | 461 | public function getWithCount(): bool 462 | { 463 | return $this->evaluate($this->withCount); 464 | } 465 | 466 | public function getMultiple(): bool 467 | { 468 | return $this->evaluate( 469 | is_null($this->multiple) ? $this->getRelationship() instanceof BelongsToMany : $this->evaluate($this->multiple) 470 | ); 471 | } 472 | 473 | public function getClearable(): bool 474 | { 475 | return $this->evaluate($this->clearable); 476 | } 477 | 478 | public function getAlwaysOpen(): bool 479 | { 480 | return $this->evaluate($this->alwaysOpen); 481 | } 482 | 483 | public function getEnableBranchNode(): bool 484 | { 485 | return $this->evaluate($this->enableBranchNode); 486 | } 487 | 488 | public function getDefaultOpenLevel(): int 489 | { 490 | return $this->evaluate($this->defaultOpenLevel); 491 | } 492 | 493 | public function getEmptyLabel(): string 494 | { 495 | return $this->getNoSearchResultsMessage(); 496 | } 497 | 498 | public function getDirection(): string 499 | { 500 | return $this->evaluate($this->direction); 501 | } 502 | 503 | public function getDisabledOptions(): array 504 | { 505 | return $this->evaluate($this->disabledOptions); 506 | } 507 | 508 | public function getHiddenOptions(): array 509 | { 510 | return $this->evaluate($this->hiddenOptions); 511 | } 512 | 513 | public function getCreateOptionActionForm(Form $form): array|Form|null 514 | { 515 | return $this->evaluate($this->createOptionActionForm, ['form' => $form]); 516 | } 517 | 518 | public function hasCreateOptionActionFormSchema(): bool 519 | { 520 | return (bool) $this->createOptionActionForm; 521 | } 522 | 523 | public function getCreateOptionModalHeading(): ?string 524 | { 525 | return $this->evaluate($this->createOptionModalHeading); 526 | } 527 | 528 | public function createOptionForm(array|Closure|null $schema): static 529 | { 530 | $this->createOptionActionForm = $schema; 531 | 532 | return $this; 533 | } 534 | 535 | public function getCreateOptionActionName(): string 536 | { 537 | return 'createOption'; 538 | } 539 | 540 | public function getCreateOptionUsing(): ?Closure 541 | { 542 | return $this->createOptionUsing; 543 | } 544 | 545 | public function createOptionUsing(Closure $callback): static 546 | { 547 | $this->createOptionUsing = $callback; 548 | 549 | return $this; 550 | } 551 | 552 | public function getCreateOptionAction(): ?Action 553 | { 554 | if ($this->isDisabled()) { 555 | return null; 556 | } 557 | 558 | if (! $this->hasCreateOptionActionFormSchema()) { 559 | return null; 560 | } 561 | 562 | $action = Action::make($this->getCreateOptionActionName()) 563 | ->form(function (SelectTree $component, Form $form): array|Form|null { 564 | return $component->getCreateOptionActionForm($form->model( 565 | $component->getRelationship() ? $component->getRelationship()->getModel()::class : null, 566 | )); 567 | }) 568 | ->action(static function (Action $action, array $arguments, SelectTree $component, array $data, ComponentContainer $form) { 569 | if (! $component->getCreateOptionUsing()) { 570 | throw new Exception("Select field [{$component->getStatePath()}] must have a [createOptionUsing()] closure set."); 571 | } 572 | 573 | $createdOptionKey = $component->evaluate($component->getCreateOptionUsing(), [ 574 | 'data' => $data, 575 | 'form' => $form, 576 | ]); 577 | 578 | $state = $component->getMultiple() 579 | ? [ 580 | ...$component->getState() ?? [], 581 | $createdOptionKey, 582 | ] 583 | : $createdOptionKey; 584 | 585 | $component->state($state); 586 | $component->callAfterStateUpdated(); 587 | 588 | if (! ($arguments['another'] ?? false)) { 589 | return; 590 | } 591 | 592 | $action->callAfter(); 593 | 594 | $form->fill(); 595 | 596 | $action->halt(); 597 | }) 598 | ->color('gray') 599 | ->icon(FilamentIcon::resolve('forms::components.select.actions.create-option') ?? 'heroicon-m-plus') 600 | ->iconButton() 601 | ->modalHeading($this->getCreateOptionModalHeading() ?? __('filament-forms::components.select.actions.create_option.modal.heading')) 602 | ->modalSubmitActionLabel(__('filament-forms::components.select.actions.create_option.modal.actions.create.label')) 603 | ->extraModalFooterActions(fn (Action $action, SelectTree $component): array => $component->getMultiple() ? [ 604 | $action->makeModalSubmitAction('createAnother', arguments: ['another' => true]) 605 | ->label(__('filament-forms::components.select.actions.create_option.modal.actions.create_another.label')), 606 | ] : []); 607 | 608 | if ($this->modifyManageOptionActionsUsing) { 609 | $action = $this->evaluate($this->modifyManageOptionActionsUsing, [ 610 | 'action' => $action, 611 | ]) ?? $action; 612 | } 613 | 614 | if ($this->modifyCreateOptionActionUsing) { 615 | $action = $this->evaluate($this->modifyCreateOptionActionUsing, [ 616 | 'action' => $action, 617 | ]) ?? $action; 618 | } 619 | 620 | return $action; 621 | } 622 | 623 | public function createOptionModalHeading(string|Closure|null $heading): static 624 | { 625 | $this->createOptionModalHeading = $heading; 626 | 627 | return $this; 628 | } 629 | 630 | public function treeKey(string $treeKey): static 631 | { 632 | $this->treeKey = $treeKey; 633 | 634 | return $this; 635 | } 636 | 637 | public function getTreeKey(): string 638 | { 639 | return $this->evaluate($this->treeKey); 640 | } 641 | } 642 | -------------------------------------------------------------------------------- /src/Testing/TestsFilamentSelectTree.php: -------------------------------------------------------------------------------- 1 |