├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── coverage.yml │ ├── php-cs-fixer.yml │ ├── phpunit.yml │ └── update-changelog.yml ├── .gitignore ├── .php-cs-fixer.dist.php ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── config.php ├── helpers └── generate-widgets.php ├── js ├── dist │ ├── root-algolia-alpine.js │ ├── root-algolia.js │ ├── root-alpine.js │ └── root.js ├── package.json ├── src │ ├── factory.js │ ├── root-algolia-alpine.js │ ├── root-algolia.js │ ├── root-alpine.js │ └── root.js └── yarn.lock ├── phpunit.xml ├── resources └── views │ ├── breadcrumb.blade.php │ ├── clear-refinements.blade.php │ ├── connected-component.blade.php │ ├── context.blade.php │ ├── current-refinements.blade.php │ ├── hierarchical-menu.blade.php │ ├── highlight.blade.php │ ├── hit.blade.php │ ├── hits.blade.php │ ├── menu-select.blade.php │ ├── menu.blade.php │ ├── numeric-menu.blade.php │ ├── pagination.blade.php │ ├── range-input.blade.php │ ├── range-slider.blade.php │ ├── rating-menu.blade.php │ ├── refinement-list.blade.php │ ├── refinement.blade.php │ ├── search-box.blade.php │ ├── snippet.blade.php │ ├── sort-by.blade.php │ └── toggle-refinement.blade.php ├── src ├── BladeInstantSearch.php ├── Components │ ├── Breadcrumb.php │ ├── ClearRefinements.php │ ├── CurrentRefinements.php │ ├── HierarchicalMenu.php │ ├── Highlight.php │ ├── Hit.php │ ├── Hits.php │ ├── InstantSearch.php │ ├── Menu.php │ ├── MenuSelect.php │ ├── NumericMenu.php │ ├── Pagination.php │ ├── RangeInput.php │ ├── RangeSlider.php │ ├── RatingMenu.php │ ├── Refinement.php │ ├── RefinementList.php │ ├── SearchBox.php │ ├── Snippet.php │ ├── SortBy.php │ ├── ToggleRefinement.php │ └── Widget.php ├── Facades │ └── BladeInstantSearch.php └── Providers │ └── BladeInstantSearchProvider.php └── tests ├── .gitkeep ├── Feature └── ComponentRenderingTest.php └── TestCase.php /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **What version does this affect?** 14 | - Laravel Version: [e.g. 5.8.0] 15 | - Package Version: [e.g. 1.5.0] 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior: 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new feature idea or improvement 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Code Coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | coverage: 10 | runs-on: ubuntu-latest 11 | 12 | name: Publish code coverage 13 | 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v2 17 | 18 | - name: Setup PHP 19 | uses: shivammathur/setup-php@v2 20 | with: 21 | php-version: 8.2 22 | extensions: dom, curl, libxml, mbstring, zip, pcntl, bcmath, intl, iconv 23 | coverage: pcov 24 | 25 | - name: Cache dependencies 26 | uses: actions/cache@v2 27 | with: 28 | path: | 29 | vendor 30 | ${{ steps.composer-cache-files-dir.outputs.dir }} 31 | key: ${{ runner.os }}-composer-${{ hashFiles('composer.json') }} 32 | restore-keys: | 33 | ${{ runner.os }}-composer- 34 | 35 | - name: Install dependencies 36 | env: 37 | COMPOSER_DISCARD_CHANGES: true 38 | run: composer require --no-progress --no-interaction --prefer-dist --update-with-all-dependencies "laravel/framework:^10.0" 39 | 40 | - name: Run and publish code coverage 41 | uses: paambaati/codeclimate-action@v5.0.0 42 | env: 43 | CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} 44 | with: 45 | coverageCommand: vendor/bin/phpunit --coverage-clover ${{ github.workspace }}/clover.xml 46 | debug: true 47 | coverageLocations: 48 | "${{github.workspace}}/clover.xml:clover" 49 | -------------------------------------------------------------------------------- /.github/workflows/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | name: Code Style 2 | 3 | on: [ pull_request, push ] 4 | 5 | jobs: 6 | coverage: 7 | runs-on: ubuntu-latest 8 | 9 | name: Run code style checks 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | 15 | - name: Setup PHP 16 | uses: shivammathur/setup-php@v2 17 | with: 18 | php-version: 8.2 19 | extensions: dom, curl, libxml, mbstring, zip, pcntl, bcmath, intl, iconv 20 | 21 | - name: Cache dependencies 22 | uses: actions/cache@v2 23 | with: 24 | path: | 25 | vendor 26 | ${{ steps.composer-cache-files-dir.outputs.dir }} 27 | key: ${{ runner.os }}-composer-${{ hashFiles('composer.json') }} 28 | restore-keys: | 29 | ${{ runner.os }}-composer- 30 | 31 | - name: Install dependencies 32 | env: 33 | COMPOSER_DISCARD_CHANGES: true 34 | run: composer require --no-progress --no-interaction --prefer-dist --update-with-all-dependencies "laravel/framework:^10.0" 35 | 36 | - name: Run PHP CS Fixer 37 | run: ./vendor/bin/php-cs-fixer fix --diff --dry-run 38 | -------------------------------------------------------------------------------- /.github/workflows/phpunit.yml: -------------------------------------------------------------------------------- 1 | name: PHPUnit 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 14 * * 3' # Run Wednesdays at 2pm EST 8 | 9 | jobs: 10 | php-tests: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | php: [ 8.1, 8.2, 8.3 ] 16 | laravel: [ ^9.0, ^10.0, ^11.0 ] 17 | dependency-version: [ stable, lowest ] 18 | exclude: 19 | - laravel: ^11.0 20 | php: 8.1 21 | - laravel: ^9.0 22 | dependency-version: lowest 23 | 24 | name: "${{ matrix.php }} / ${{ matrix.laravel }} (${{ matrix.dependency-version }})" 25 | 26 | steps: 27 | - name: Checkout code 28 | uses: actions/checkout@v2 29 | 30 | - name: Setup PHP 31 | uses: shivammathur/setup-php@v2 32 | with: 33 | php-version: ${{ matrix.php }} 34 | extensions: dom, curl, libxml, mbstring, zip, pcntl, bcmath, intl, iconv 35 | tools: composer:v2 36 | 37 | - name: Register composer cache directory 38 | id: composer-cache-files-dir 39 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 40 | 41 | - name: Cache dependencies 42 | uses: actions/cache@v2 43 | with: 44 | path: | 45 | vendor 46 | ${{ steps.composer-cache-files-dir.outputs.dir }} 47 | key: ${{ runner.os }}-composer-${{ hashFiles('composer.json') }} 48 | restore-keys: | 49 | ${{ runner.os }}-composer- 50 | 51 | - name: Install dependencies 52 | env: 53 | COMPOSER_DISCARD_CHANGES: true 54 | run: | 55 | composer config minimum-stability ${{ matrix.minimum-stability }} 56 | composer require --no-progress --no-interaction --prefer-dist --update-with-all-dependencies "laravel/framework:${{ matrix.laravel }}" 57 | composer update --no-progress --no-interaction --prefer-dist --with-all-dependencies --prefer-${{ matrix.dependency-version }} 58 | 59 | - name: Execute tests 60 | run: vendor/bin/phpunit 61 | -------------------------------------------------------------------------------- /.github/workflows/update-changelog.yml: -------------------------------------------------------------------------------- 1 | name: Update Changelog 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | jobs: 8 | update-publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | repository: ${{ github.event.repository.full_name }} 14 | ref: 'main' 15 | 16 | - name: Update changelog 17 | uses: thomaseizinger/keep-a-changelog-new-release@v1 18 | with: 19 | version: ${{ github.event.release.tag_name }} 20 | 21 | - name: Commit changelog back to repo 22 | uses: EndBug/add-and-commit@v8 23 | with: 24 | add: 'CHANGELOG.md' 25 | message: ${{ github.event.release.tag_name }} 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | vendor/ 3 | /js/node_modules 4 | composer.lock 5 | .phpunit.result.cache 6 | .php-cs-fixer.cache 7 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | setRiskyAllowed(true) 7 | ->setIndent("\t") 8 | ->setLineEnding("\n") 9 | ->setRules([ 10 | '@PSR2' => true, 11 | 'function_declaration' => [ 12 | 'closure_function_spacing' => 'none', 13 | 'closure_fn_spacing' => 'none', 14 | ], 15 | 'ordered_imports' => [ 16 | 'sort_algorithm' => 'alpha', 17 | ], 18 | 'array_indentation' => true, 19 | 'braces' => [ 20 | 'allow_single_line_closure' => true, 21 | ], 22 | 'no_break_comment' => false, 23 | 'return_type_declaration' => [ 24 | 'space_before' => 'none', 25 | ], 26 | 'blank_line_after_opening_tag' => true, 27 | 'compact_nullable_typehint' => true, 28 | 'cast_spaces' => true, 29 | 'concat_space' => [ 30 | 'spacing' => 'none', 31 | ], 32 | 'declare_equal_normalize' => [ 33 | 'space' => 'none', 34 | ], 35 | 'function_typehint_space' => true, 36 | 'new_with_braces' => true, 37 | 'method_argument_space' => true, 38 | 'no_empty_statement' => true, 39 | 'no_empty_comment' => true, 40 | 'no_empty_phpdoc' => true, 41 | 'no_extra_blank_lines' => [ 42 | 'tokens' => [ 43 | 'extra', 44 | 'use', 45 | 'use_trait', 46 | 'return', 47 | ], 48 | ], 49 | 'no_leading_import_slash' => true, 50 | 'no_leading_namespace_whitespace' => true, 51 | 'no_blank_lines_after_class_opening' => true, 52 | 'no_blank_lines_after_phpdoc' => true, 53 | 'no_whitespace_in_blank_line' => false, 54 | 'no_whitespace_before_comma_in_array' => true, 55 | 'no_useless_else' => true, 56 | 'no_useless_return' => true, 57 | 'single_trait_insert_per_statement' => true, 58 | 'psr_autoloading' => true, 59 | 'dir_constant' => true, 60 | 'single_line_comment_style' => [ 61 | 'comment_types' => ['hash'], 62 | ], 63 | 'include' => true, 64 | 'is_null' => true, 65 | 'linebreak_after_opening_tag' => true, 66 | 'lowercase_cast' => true, 67 | 'lowercase_static_reference' => true, 68 | 'magic_constant_casing' => true, 69 | 'magic_method_casing' => true, 70 | 'class_attributes_separation' => [ 71 | // TODO: This can be reverted when https://github.com/FriendsOfPHP/PHP-CS-Fixer/pull/5869 is merged 72 | 'elements' => ['const' => 'one', 'method' => 'one', 'property' => 'one'], 73 | ], 74 | 'modernize_types_casting' => true, 75 | 'native_function_casing' => true, 76 | 'native_function_type_declaration_casing' => true, 77 | 'no_alias_functions' => true, 78 | 'no_multiline_whitespace_around_double_arrow' => true, 79 | 'multiline_whitespace_before_semicolons' => true, 80 | 'no_short_bool_cast' => true, 81 | 'no_unused_imports' => true, 82 | 'no_php4_constructor' => true, 83 | 'no_singleline_whitespace_before_semicolons' => true, 84 | 'no_spaces_around_offset' => true, 85 | 'no_trailing_comma_in_list_call' => true, 86 | 'no_trailing_comma_in_singleline_array' => true, 87 | 'normalize_index_brace' => true, 88 | 'object_operator_without_whitespace' => true, 89 | 'phpdoc_annotation_without_dot' => true, 90 | 'phpdoc_indent' => true, 91 | 'phpdoc_no_package' => true, 92 | 'phpdoc_no_access' => true, 93 | 'phpdoc_no_useless_inheritdoc' => true, 94 | 'phpdoc_single_line_var_spacing' => true, 95 | 'phpdoc_trim' => true, 96 | 'phpdoc_types' => true, 97 | 'semicolon_after_instruction' => true, 98 | 'array_syntax' => [ 99 | 'syntax' => 'short', 100 | ], 101 | 'list_syntax' => [ 102 | 'syntax' => 'short', 103 | ], 104 | 'short_scalar_cast' => true, 105 | 'single_blank_line_before_namespace' => true, 106 | 'single_quote' => true, 107 | 'standardize_not_equals' => true, 108 | 'ternary_operator_spaces' => true, 109 | 'whitespace_after_comma_in_array' => true, 110 | 'not_operator_with_successor_space' => true, 111 | 'trailing_comma_in_multiline' => true, 112 | 'trim_array_spaces' => true, 113 | 'binary_operator_spaces' => true, 114 | 'unary_operator_spaces' => true, 115 | 'php_unit_method_casing' => [ 116 | 'case' => 'snake_case', 117 | ], 118 | 'php_unit_test_annotation' => [ 119 | 'style' => 'prefix', 120 | ], 121 | ]) 122 | ->setFinder( 123 | PhpCsFixer\Finder::create() 124 | ->exclude('.circleci') 125 | ->exclude('bin') 126 | ->exclude('node_modules') 127 | ->exclude('vendor') 128 | ->notPath('.phpstorm.meta.php') 129 | ->notPath('_ide_helper.php') 130 | ->notPath('artisan') 131 | ->in(__DIR__) 132 | ); 133 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes **after `0.4.1`** will be documented in this file following 4 | the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 5 | 6 | ## [Unreleased] 7 | 8 | ## [0.5.2] - 2025-05-12 9 | 10 | ## [0.5.1] - 2025-05-12 11 | 12 | ## [0.5.0] - 2024-03-12 13 | 14 | ### Added 15 | 16 | - Added Laravel 11 support 17 | - Added basic tests 18 | 19 | # Keep a Changelog Syntax 20 | 21 | - `Added` for new features. 22 | - `Changed` for changes in existing functionality. 23 | - `Deprecated` for soon-to-be removed features. 24 | - `Removed` for now removed features. 25 | - `Fixed` for any bug fixes. 26 | - `Security` in case of vulnerabilities. 27 | 28 | [Unreleased]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.5.2...HEAD 29 | 30 | [0.5.2]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.5.1...0.5.2 31 | 32 | [0.5.1]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.5.0...0.5.1 33 | 34 | [0.5.0]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.4.1...0.5.0 35 | 36 | [0.4.1]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.4.0...0.4.1 37 | 38 | [0.4.0]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.3.0...0.4.0 39 | 40 | [0.3.0]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.2.0...0.3.0 41 | 42 | [0.2.0]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.1.2...0.2.0 43 | 44 | [0.1.2]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.1.1...0.1.2 45 | 46 | [0.1.1]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.1.0...0.1.1 47 | 48 | [0.0.1]: https://github.com/InterNACHI/blade-alpine-instantsearch/compare/0.1.0...0.1.0 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 InterNACHI 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Blade/Alpine InstantSearch 2 | 3 |
4 | 5 | Latest Stable Release 9 | 10 | 11 | MIT Licensed 15 | 16 |
17 | 18 | This is a work-in-progress package to allow you to implement [Algolia InstantSearch](https://www.algolia.com/doc/api-reference/widgets/instantsearch/js/) 19 | entirely with [Laravel Blade components](https://laravel.com/docs/8.x/blade). 20 | 21 | ## Usage 22 | 23 | ### Components 24 | 25 | Not all components are implemented, and most of the UI is likely to change before a 1.0 26 | release. The current implementation is a proof-of-concept that we'll be refining in some 27 | internal tools over the coming months. All components should work in 28 | [renderless mode](#renderless-mode), but UI has only been implemented for the following: 29 | 30 | - `` — the wrapper that provides configuration and context 31 | - `` — the search input 32 | - `` — rendering search results/hits 33 | - `` — rendering a specific attribute in a hit 34 | - `` — rendering a specific attribute highlighted based on input 35 | - `` — Filtering by numeric values (like price/votes/etc) 36 | - `` — Filtering by tags/categories/etc 37 | - `` — Paginating results 38 | 39 | All components map as closely to [InstantSearch.js](https://www.algolia.com/doc/api-reference/widgets/js/) 40 | as possible (in fact, much of the API was autogenerated from the JS documentation). For 41 | now, it's probably best to refer to the JS docs for configuration reference. 42 | 43 | ### Alpine 44 | 45 | Under the hood, all components use [Alpine.js v3](https://github.com/alpinejs/alpine) to 46 | handle state and rendering. For example, the search box component uses Alpine's 47 | [`x-model`](https://github.com/alpinejs/alpine#x-model) to track the `query` value, 48 | and [`x-on:input`](https://github.com/alpinejs/alpine#x-on) to pass that value to the 49 | instantsearch `refine()` method. The looks something like: 50 | 51 | ```html 52 | 58 | ``` 59 | 60 | Under the hood, this package injects itself into the Blade component's 61 | [attributes](https://laravel.com/docs/8.x/blade#component-attributes) to connect 62 | to the instantsearch instance—everything else is just Alpine and Blade. 63 | 64 | ### Using Existing Templates 65 | 66 | All components come pre-bundled with templates that will work with any project that uses 67 | [Tailwind CSS](https://tailwindcss.com). If you want to tweak a specific template you can 68 | publish your own version with: 69 | 70 | ```bash 71 | php artisan vendor:publish --tag=instantsearch 72 | ``` 73 | 74 | ### Renderless Mode 75 | 76 | If you prefer more fine-grained control over each component, you can enable `renderless` 77 | mode which simply wires up your component state but leaves the UI entirely in your hands. 78 | 79 | You can either do this on a component-by-component basis by using a `renderless` attribute 80 | on the component: 81 | 82 | ```html 83 | 84 | 85 | 86 | ``` 87 | 88 | Or you can publish the package config file with: 89 | 90 | ```bash 91 | php artisan vendor:publish --tag=instantsearch 92 | ``` 93 | 94 | And then enable the `renderless` config option which will cause all components to work 95 | in this mode by default. 96 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "internachi/blade-alpine-instantsearch", 3 | "description": "Algolia instant search as Blade/Alpine.js components", 4 | "keywords": [ 5 | "laravel", 6 | "algolia", 7 | "instantsearch" 8 | ], 9 | "type": "library", 10 | "license": "MIT", 11 | "autoload": { 12 | "psr-4": { 13 | "InterNACHI\\BladeInstantSearch\\": "src/" 14 | } 15 | }, 16 | "autoload-dev": { 17 | "psr-4": { 18 | "InterNACHI\\BladeInstantSearch\\Tests\\": "tests/" 19 | } 20 | }, 21 | "minimum-stability": "dev", 22 | "extra": { 23 | "laravel": { 24 | "providers": [ 25 | "InterNACHI\\BladeInstantSearch\\Providers\\BladeInstantSearchProvider" 26 | ] 27 | } 28 | }, 29 | "require": { 30 | "php": ">=7.4", 31 | "illuminate/view": "^8.71|^9|^10|^11|dev-master", 32 | "illuminate/support": "^8.71|^9|^10|^11|dev-master" 33 | }, 34 | "require-dev": { 35 | "orchestra/testbench": "^6|^7|^8|^9|9.x-dev|dev-master", 36 | "phpunit/phpunit": "^9.0|^10.5", 37 | "friendsofphp/php-cs-fixer": "^3.39" 38 | }, 39 | "scripts": { 40 | "fix-style": "vendor/bin/php-cs-fixer fix", 41 | "check-style": "vendor/bin/php-cs-fixer fix --diff --dry-run" 42 | }, 43 | "archive": { 44 | "exclude": [ 45 | "/helpers", 46 | "/tests", 47 | "/js/src", 48 | "/js/package.json", 49 | "/js/yarn.lock" 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | true, 21 | 'bundle_algolia' => true, 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Render Mode 26 | |-------------------------------------------------------------------------- 27 | | 28 | | The package ships with default component styles that work well with any 29 | | site designed using Tailwind CSS. If you would like to have full control 30 | | over your templates, you may enable "renderless" mode, which will simply 31 | | wire up the Alpine state for you and leave the rest of the UI up to you. 32 | */ 33 | 'renderless' => false, 34 | 35 | ]; 36 | -------------------------------------------------------------------------------- /helpers/generate-widgets.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | combine($matches[2]) 187 | ->mapWithKeys(fn($value, $key) => [ucfirst($key) => $value]) 188 | ->map(function($definition) { 189 | preg_match_all('/^\s*(?P[a-z0-9]+):\s*(?P.*?),/im', $definition, $matches); 190 | return collect($matches['argument']) 191 | ->combine($matches['type']) 192 | ->map(fn($type) => Str::of($type)) 193 | ->map(function(Stringable $type) { 194 | // Skip types that are incompatible with the PHP implementation 195 | if ($type->contains(['HTMLElement', 'object', 'function'])) { 196 | return null; 197 | } 198 | 199 | if ($type->endsWith('[]')) { 200 | return '?array'; 201 | } 202 | 203 | $map = [ 204 | 'string' => '?string', 205 | 'number' => '?int', 206 | 'boolean' => '?bool', 207 | ]; 208 | 209 | return $map[(string) $type]; 210 | }) 211 | ->filter(); 212 | }) 213 | ->each(function(Collection $arguments, string $name) { 214 | $constructor_arguments = $arguments 215 | ->map(fn($type, $name) => "{$type} \${$name} = null") 216 | ->implode(",\n\t\t"); 217 | 218 | $compact_lines = $arguments 219 | ->map(fn($type, $name) => "'{$name}'") 220 | ->implode(",\n\t\t\t"); 221 | 222 | $view = Str::kebab($name); 223 | 224 | $generated_class = <<setWidgetData(array_filter(compact( 235 | {$compact_lines} 236 | ))); 237 | } 238 | 239 | public function render() 240 | { 241 | return view('instantsearch::{$view}'); 242 | } 243 | } 244 | PHP; 245 | 246 | $view_hints = $arguments 247 | ->map(fn($type, $name) => "{{-- {$name} ({$type}) --}}") 248 | ->implode("\n"); 249 | 250 | $generated_view = << 252 | {{ \$slot }} 253 | 254 | 255 | {$view_hints} 256 | HTML; 257 | 258 | $class_file = realpath(__DIR__.'/../src/Components').'/'.$name.'.php'; 259 | $view_file = realpath(__DIR__.'/../resources/views').'/'.$view.'.blade.php'; 260 | 261 | if (file_exists($class_file)) { 262 | echo "SKIPPING: $name\n\n$generated_class\n\n"; 263 | } else { 264 | file_put_contents($class_file, $generated_class); 265 | } 266 | 267 | if (! file_exists($view_file)) { 268 | file_put_contents($view_file, $generated_view); 269 | } 270 | }); 271 | -------------------------------------------------------------------------------- /js/dist/root-alpine.js: -------------------------------------------------------------------------------- 1 | var BladeAlpineInstantSearch=function(){var e,t,n,r,i=Object.create,o=Object.defineProperty,a=Object.getPrototypeOf,s=Object.prototype.hasOwnProperty,l=Object.getOwnPropertyNames,c=Object.getOwnPropertyDescriptor,u=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),f=u(e=>{function t(e,t){const n=Object.create(null),r=e.split(",");for(let e=0;e!!n[e.toLowerCase()]:e=>!!n[e]}Object.defineProperty(e,"__esModule",{value:!0});var n={1:"TEXT",2:"CLASS",4:"STYLE",8:"PROPS",16:"FULL_PROPS",32:"HYDRATE_EVENTS",64:"STABLE_FRAGMENT",128:"KEYED_FRAGMENT",256:"UNKEYED_FRAGMENT",512:"NEED_PATCH",1024:"DYNAMIC_SLOTS",2048:"DEV_ROOT_FRAGMENT",[-1]:"HOISTED",[-2]:"BAIL"},r=t("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt"),i="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",o=t(i),a=t(i+",async,autofocus,autoplay,controls,default,defer,disabled,hidden,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected"),s=/[>/="'\u0009\u000a\u000c\u0020]/,l={},c=t("animation-iteration-count,border-image-outset,border-image-slice,border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,columns,flex,flex-grow,flex-positive,flex-shrink,flex-negative,flex-order,grid-row,grid-row-end,grid-row-span,grid-row-start,grid-column,grid-column-end,grid-column-span,grid-column-start,font-weight,line-clamp,line-height,opacity,order,orphans,tab-size,widows,z-index,zoom,fill-opacity,flood-opacity,stop-opacity,stroke-dasharray,stroke-dashoffset,stroke-miterlimit,stroke-opacity,stroke-width"),u=t("accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap"),f=/;(?![^(]*\))/g,d=/:(.+)/;function p(e){const t={};return e.split(f).forEach(e=>{if(e){const n=e.split(d);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}var h=t("html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot"),_=t("svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view"),g=t("area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr"),m=/["'&<>]/,y=/^-?>||--!>|j(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((e,[t,n])=>(e[`${t} =>`]=n,e),{})}:C(t)?{[`Set(${t.size})`]:[...t.values()]}:!P(t)||A(t)||L(t)?t:String(t),w=Object.freeze({}),O=Object.freeze([]),E=/^on[^a-z]/,k=Object.assign,S=Object.prototype.hasOwnProperty,A=Array.isArray,j=e=>"[object Map]"===$(e),C=e=>"[object Set]"===$(e),R=e=>e instanceof Date,M=e=>"function"==typeof e,T=e=>"string"==typeof e,P=e=>null!==e&&"object"==typeof e,N=Object.prototype.toString,$=e=>N.call(e),L=e=>"[object Object]"===$(e),I=t(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),z=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},D=/-(\w)/g,F=z(e=>e.replace(D,(e,t)=>t?t.toUpperCase():"")),B=/\B([A-Z])/g,q=z(e=>e.replace(B,"-$1").toLowerCase()),V=z(e=>e.charAt(0).toUpperCase()+e.slice(1)),W=z(e=>e?`on${V(e)}`:"");e.EMPTY_ARR=O,e.EMPTY_OBJ=w,e.NO=()=>!1,e.NOOP=()=>{},e.PatchFlagNames=n,e.babelParserDefaultPlugins=["bigInt","optionalChaining","nullishCoalescingOperator"],e.camelize=F,e.capitalize=V,e.def=(e,t,n)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},e.escapeHtml=function(e){const t=""+e,n=m.exec(t);if(!n)return t;let r,i,o="",a=0;for(i=n.index;i=t){for(let a=e-2;a<=e+2||n>i;a++){if(a<0||a>=r.length)continue;const s=a+1;o.push(`${s}${" ".repeat(Math.max(3-String(s).length,0))}| ${r[a]}`);const l=r[a].length;if(a===e){const e=t-(i-l)+1,r=Math.max(1,n>i?l-e:n-t);o.push(" | "+" ".repeat(e)+"^".repeat(r))}else if(a>e){if(n>i){const e=Math.max(Math.min(n-i,l),1);o.push(" | "+"^".repeat(e))}i+=l+1}}break}return o.join("\n")},e.getGlobalThis=()=>b||(b="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{}),e.hasChanged=(e,t)=>e!==t&&(e==e||t==t),e.hasOwn=(e,t)=>S.call(e,t),e.hyphenate=q,e.invokeArrayFns=(e,t)=>{for(let n=0;nT(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,e.isKnownAttr=u,e.isMap=j,e.isModelListener=e=>e.startsWith("onUpdate:"),e.isNoUnitNumericStyleProp=c,e.isObject=P,e.isOn=e=>E.test(e),e.isPlainObject=L,e.isPromise=e=>P(e)&&M(e.then)&&M(e.catch),e.isReservedProp=I,e.isSSRSafeAttrName=function(e){if(l.hasOwnProperty(e))return l[e];const t=s.test(e);return t&&console.error(`unsafe attribute name: ${e}`),l[e]=!t},e.isSVGTag=_,e.isSet=C,e.isSpecialBooleanAttr=o,e.isString=T,e.isSymbol=e=>"symbol"==typeof e,e.isVoidTag=g,e.looseEqual=v,e.looseIndexOf=function(e,t){return e.findIndex(e=>v(e,t))},e.makeMap=t,e.normalizeClass=function e(t){let n="";if(T(t))n=t;else if(A(t))for(let r=0;r{const n=e.indexOf(t);n>-1&&e.splice(n,1)},e.slotFlagsText={1:"STABLE",2:"DYNAMIC",3:"FORWARDED"},e.stringifyStyle=function(e){let t="";if(!e)return t;for(const n in e){const r=e[n],i=n.startsWith("--")?n:q(n);(T(r)||"number"==typeof r&&c(i))&&(t+=`${i}:${r};`)}return t},e.toDisplayString=e=>null==e?"":P(e)?JSON.stringify(e,x,2):String(e),e.toHandlerKey=W,e.toNumber=e=>{const t=parseFloat(e);return isNaN(t)?e:t},e.toRawType=e=>$(e).slice(8,-1),e.toTypeString=$}),d=u((e,t)=>{t.exports=f()}),p=u(e=>{Object.defineProperty(e,"__esModule",{value:!0});var t,n=d(),r=new WeakMap,i=[],o=Symbol("iterate"),a=Symbol("Map key iterate");function s(e,r=n.EMPTY_OBJ){(function(e){return e&&!0===e._isEffect})(e)&&(e=e.raw);const o=function(e,n){const r=function(){if(!r.active)return e();if(!i.includes(r)){c(r);try{return h(),i.push(r),t=r,e()}finally{i.pop(),_(),t=i[i.length-1]}}};return r.id=l++,r.allowRecurse=!!n.allowRecurse,r._isEffect=!0,r.active=!0,r.raw=e,r.deps=[],r.options=n,r}(e,r);return r.lazy||o(),o}var l=0;function c(e){const{deps:t}=e;if(t.length){for(let n=0;n{e&&e.forEach(e=>{(e!==t||e.allowRecurse)&&d.add(e)})};if("clear"===i)f.forEach(p);else if("length"===s&&n.isArray(e))f.forEach((e,t)=>{("length"===t||t>=l)&&p(e)});else switch(void 0!==s&&p(f.get(s)),i){case"add":n.isArray(e)?n.isIntegerKey(s)&&p(f.get("length")):(p(f.get(o)),n.isMap(e)&&p(f.get(a)));break;case"delete":n.isArray(e)||(p(f.get(o)),n.isMap(e)&&p(f.get(a)));break;case"set":n.isMap(e)&&p(f.get(o))}d.forEach(t=>{t.options.onTrigger&&t.options.onTrigger({effect:t,target:e,key:s,type:i,newValue:l,oldValue:c,oldTarget:u}),t.options.scheduler?t.options.scheduler(t):t()})}var y=n.makeMap("__proto__,__v_isRef,__isVue"),v=new Set(Object.getOwnPropertyNames(Symbol).map(e=>Symbol[e]).filter(n.isSymbol)),b=k(),x=k(!1,!0),w=k(!0),O=k(!0,!0),E={};function k(e=!1,t=!1){return function(r,i,o){if("__v_isReactive"===i)return!e;if("__v_isReadonly"===i)return e;if("__v_raw"===i&&o===(e?t?ie:re:t?ne:te).get(r))return r;const a=n.isArray(r);if(!e&&a&&n.hasOwn(E,i))return Reflect.get(E,i,o);const s=Reflect.get(r,i,o);return(n.isSymbol(i)?v.has(i):y(i))?s:(e||g(r,"get",i),t?s:pe(s)?a&&n.isIntegerKey(i)?s:s.value:n.isObject(s)?e?ae(s):oe(s):s)}}function S(e=!1){return function(t,r,i,o){let a=t[r];if(!e&&(i=fe(i),a=fe(a),!n.isArray(t)&&pe(a)&&!pe(i)))return a.value=i,!0;const s=n.isArray(t)&&n.isIntegerKey(r)?Number(r){const t=Array.prototype[e];E[e]=function(...e){const n=fe(this);for(let e=0,t=this.length;e{const t=Array.prototype[e];E[e]=function(...e){p();const n=t.apply(this,e);return _(),n}});var A={get:b,set:S(),deleteProperty:function(e,t){const r=n.hasOwn(e,t),i=e[t],o=Reflect.deleteProperty(e,t);return o&&r&&m(e,"delete",t,void 0,i),o},has:function(e,t){const r=Reflect.has(e,t);return n.isSymbol(t)&&v.has(t)||g(e,"has",t),r},ownKeys:function(e){return g(e,"iterate",n.isArray(e)?"length":o),Reflect.ownKeys(e)}},j={get:w,set:(e,t)=>(console.warn(`Set operation on key "${String(t)}" failed: target is readonly.`,e),!0),deleteProperty:(e,t)=>(console.warn(`Delete operation on key "${String(t)}" failed: target is readonly.`,e),!0)},C=n.extend({},A,{get:x,set:S(!0)}),R=n.extend({},j,{get:O}),M=e=>n.isObject(e)?oe(e):e,T=e=>n.isObject(e)?ae(e):e,P=e=>e,N=e=>Reflect.getPrototypeOf(e);function $(e,t,n=!1,r=!1){const i=fe(e=e.__v_raw),o=fe(t);t!==o&&!n&&g(i,"get",t),!n&&g(i,"get",o);const{has:a}=N(i),s=r?P:n?T:M;return a.call(i,t)?s(e.get(t)):a.call(i,o)?s(e.get(o)):void(e!==i&&e.get(t))}function L(e,t=!1){const n=this.__v_raw,r=fe(n),i=fe(e);return e!==i&&!t&&g(r,"has",e),!t&&g(r,"has",i),e===i?n.has(e):n.has(e)||n.has(i)}function I(e,t=!1){return e=e.__v_raw,!t&&g(fe(e),"iterate",o),Reflect.get(e,"size",e)}function z(e){e=fe(e);const t=fe(this);return N(t).has.call(t,e)||(t.add(e),m(t,"add",e,e)),this}function D(e,t){t=fe(t);const r=fe(this),{has:i,get:o}=N(r);let a=i.call(r,e);a?ee(r,i,e):(e=fe(e),a=i.call(r,e));const s=o.call(r,e);return r.set(e,t),a?n.hasChanged(t,s)&&m(r,"set",e,t,s):m(r,"add",e,t),this}function F(e){const t=fe(this),{has:n,get:r}=N(t);let i=n.call(t,e);i?ee(t,n,e):(e=fe(e),i=n.call(t,e));const o=r?r.call(t,e):void 0,a=t.delete(e);return i&&m(t,"delete",e,void 0,o),a}function B(){const e=fe(this),t=0!==e.size,r=n.isMap(e)?new Map(e):new Set(e),i=e.clear();return t&&m(e,"clear",void 0,void 0,r),i}function q(e,t){return function(n,r){const i=this,a=i.__v_raw,s=fe(a),l=t?P:e?T:M;return!e&&g(s,"iterate",o),a.forEach((e,t)=>n.call(r,l(e),l(t),i))}}function V(e,t,r){return function(...i){const s=this.__v_raw,l=fe(s),c=n.isMap(l),u="entries"===e||e===Symbol.iterator&&c,f="keys"===e&&c,d=s[e](...i),p=r?P:t?T:M;return!t&&g(l,"iterate",f?a:o),{next(){const{value:e,done:t}=d.next();return t?{value:e,done:t}:{value:u?[p(e[0]),p(e[1])]:p(e),done:t}},[Symbol.iterator](){return this}}}}function W(e){return function(...t){{const r=t[0]?`on key "${t[0]}" `:"";console.warn(`${n.capitalize(e)} operation ${r}failed: target is readonly.`,fe(this))}return"delete"!==e&&this}}var U={get(e){return $(this,e)},get size(){return I(this)},has:L,add:z,set:D,delete:F,clear:B,forEach:q(!1,!1)},K={get(e){return $(this,e,!1,!0)},get size(){return I(this)},has:L,add:z,set:D,delete:F,clear:B,forEach:q(!1,!0)},G={get(e){return $(this,e,!0)},get size(){return I(this,!0)},has(e){return L.call(this,e,!0)},add:W("add"),set:W("set"),delete:W("delete"),clear:W("clear"),forEach:q(!0,!1)},Y={get(e){return $(this,e,!0,!0)},get size(){return I(this,!0)},has(e){return L.call(this,e,!0)},add:W("add"),set:W("set"),delete:W("delete"),clear:W("clear"),forEach:q(!0,!0)};function H(e,t){const r=t?e?Y:K:e?G:U;return(t,i,o)=>"__v_isReactive"===i?!e:"__v_isReadonly"===i?e:"__v_raw"===i?t:Reflect.get(n.hasOwn(r,i)&&i in t?r:t,i,o)}["keys","values","entries",Symbol.iterator].forEach(e=>{U[e]=V(e,!1,!1),G[e]=V(e,!0,!1),K[e]=V(e,!1,!0),Y[e]=V(e,!0,!0)});var J={get:H(!1,!1)},Z={get:H(!1,!0)},X={get:H(!0,!1)},Q={get:H(!0,!0)};function ee(e,t,r){const i=fe(r);if(i!==r&&t.call(e,i)){const t=n.toRawType(e);console.warn(`Reactive ${t} contains both the raw and reactive versions of the same object${"Map"===t?" as keys":""}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`)}}var te=new WeakMap,ne=new WeakMap,re=new WeakMap,ie=new WeakMap;function oe(e){return e&&e.__v_isReadonly?e:se(e,!1,A,J,te)}function ae(e){return se(e,!0,j,X,re)}function se(e,t,r,i,o){if(!n.isObject(e))return console.warn(`value cannot be made reactive: ${String(e)}`),e;if(e.__v_raw&&(!t||!e.__v_isReactive))return e;const a=o.get(e);if(a)return a;const s=(l=e).__v_skip||!Object.isExtensible(l)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}(n.toRawType(l));var l;if(0===s)return e;const c=new Proxy(e,2===s?i:r);return o.set(e,c),c}function le(e){return ce(e)?le(e.__v_raw):!(!e||!e.__v_isReactive)}function ce(e){return!(!e||!e.__v_isReadonly)}function ue(e){return le(e)||ce(e)}function fe(e){return e&&fe(e.__v_raw)||e}var de=e=>n.isObject(e)?oe(e):e;function pe(e){return Boolean(e&&!0===e.__v_isRef)}function he(e,t=!1){return pe(e)?e:new class{constructor(e,t=!1){this._rawValue=e,this._shallow=t,this.__v_isRef=!0,this._value=t?e:de(e)}get value(){return g(fe(this),"get","value"),this._value}set value(e){n.hasChanged(fe(e),this._rawValue)&&(this._rawValue=e,this._value=this._shallow?e:de(e),m(fe(this),"set","value",e))}}(e,t)}function _e(e){return pe(e)?e.value:e}var ge={get:(e,t,n)=>_e(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const i=e[t];return pe(i)&&!pe(n)?(i.value=n,!0):Reflect.set(e,t,n,r)}};function me(e,t){return pe(e[t])?e[t]:new class{constructor(e,t){this._object=e,this._key=t,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(e){this._object[this._key]=e}}(e,t)}e.ITERATE_KEY=o,e.computed=function(e){let t,r;return n.isFunction(e)?(t=e,r=()=>{console.warn("Write operation failed: computed value is readonly")}):(t=e.get,r=e.set),new class{constructor(e,t,n){this._setter=t,this._dirty=!0,this.__v_isRef=!0,this.effect=s(e,{lazy:!0,scheduler:()=>{this._dirty||(this._dirty=!0,m(fe(this),"set","value"))}}),this.__v_isReadonly=n}get value(){const e=fe(this);return e._dirty&&(e._value=this.effect(),e._dirty=!1),g(e,"get","value"),e._value}set value(e){this._setter(e)}}(t,r,n.isFunction(e)||!e.set)},e.customRef=function(e){return new class{constructor(e){this.__v_isRef=!0;const{get:t,set:n}=e(()=>g(this,"get","value"),()=>m(this,"set","value"));this._get=t,this._set=n}get value(){return this._get()}set value(e){this._set(e)}}(e)},e.effect=s,e.enableTracking=h,e.isProxy=ue,e.isReactive=le,e.isReadonly=ce,e.isRef=pe,e.markRaw=function(e){return n.def(e,"__v_skip",!0),e},e.pauseTracking=p,e.proxyRefs=function(e){return le(e)?e:new Proxy(e,ge)},e.reactive=oe,e.readonly=ae,e.ref=function(e){return he(e)},e.resetTracking=_,e.shallowReactive=function(e){return se(e,!1,C,Z,ne)},e.shallowReadonly=function(e){return se(e,!0,R,Q,ie)},e.shallowRef=function(e){return he(e,!0)},e.stop=function(e){e.active&&(c(e),e.options.onStop&&e.options.onStop(),e.active=!1)},e.toRaw=fe,e.toRef=me,e.toRefs=function(e){ue(e)||console.warn("toRefs() expects a reactive object but received a plain one.");const t=n.isArray(e)?new Array(e.length):{};for(const n in e)t[n]=me(e,n);return t},e.track=g,e.trigger=m,e.triggerRef=function(e){m(fe(e),"set","value",e.value)},e.unref=_e}),h=u((e,t)=>{t.exports=p()}),_=!1,g=!1,m=[];function y(e){const t=m.indexOf(e);-1!==t&&m.splice(t,1)}function v(){_=!1,g=!0;for(let e=0;e{(void 0===t||t.includes(n))&&(r.forEach(e=>e()),delete e._x_attributeCleanups[n])})}var S=new MutationObserver(N),A=!1;function j(){S.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),A=!0}var C=[],R=!1;function M(e){if(!A)return e();(C=C.concat(S.takeRecords())).length&&!R&&(R=!0,queueMicrotask(()=>{N(C),C.length=0,R=!1})),S.disconnect(),A=!1;let t=e();return j(),t}var T=!1,P=[];function N(e){if(T)return void(P=P.concat(e));let t=[],n=[],r=new Map,i=new Map;for(let o=0;o1===e.nodeType&&t.push(e)),e[o].removedNodes.forEach(e=>1===e.nodeType&&n.push(e))),"attributes"===e[o].type)){let t=e[o].target,n=e[o].attributeName,a=e[o].oldValue,s=()=>{r.has(t)||r.set(t,[]),r.get(t).push({name:n,value:t.getAttribute(n)})},l=()=>{i.has(t)||i.set(t,[]),i.get(t).push(n)};t.hasAttribute(n)&&null===a?s():t.hasAttribute(n)?(l(),s()):l()}i.forEach((e,t)=>{k(t,e)}),r.forEach((e,t)=>{w.forEach(n=>n(t,e))});for(let e of n)t.includes(e)||O.forEach(t=>t(e));t.forEach(e=>{e._x_ignoreSelf=!0,e._x_ignore=!0});for(let e of t)n.includes(e)||e.isConnected&&(delete e._x_ignoreSelf,delete e._x_ignore,E.forEach(t=>t(e)),e._x_ignore=!0,e._x_ignoreSelf=!0);t.forEach(e=>{delete e._x_ignoreSelf,delete e._x_ignore}),t=null,n=null,r=null,i=null}function $(e){return D(z(e))}function L(e,t,n){return e._x_dataStack=[t,...z(n||e)],()=>{e._x_dataStack=e._x_dataStack.filter(e=>e!==t)}}function I(e,t){let n=e._x_dataStack[0];Object.entries(t).forEach(([e,t])=>{n[e]=t})}function z(e){return e._x_dataStack?e._x_dataStack:"function"==typeof ShadowRoot&&e instanceof ShadowRoot?z(e.host):e.parentNode?z(e.parentNode):[]}function D(e){let t=new Proxy({},{ownKeys:()=>Array.from(new Set(e.flatMap(e=>Object.keys(e)))),has:(t,n)=>e.some(e=>e.hasOwnProperty(n)),get:(n,r)=>(e.find(e=>{if(e.hasOwnProperty(r)){let n=Object.getOwnPropertyDescriptor(e,r);if(n.get&&n.get._x_alreadyBound||n.set&&n.set._x_alreadyBound)return!0;if((n.get||n.set)&&n.enumerable){let i=n.get,o=n.set,a=n;i=i&&i.bind(t),o=o&&o.bind(t),i&&(i._x_alreadyBound=!0),o&&(o._x_alreadyBound=!0),Object.defineProperty(e,r,{...a,get:i,set:o})}return!0}return!1})||{})[r],set:(t,n,r)=>{let i=e.find(e=>e.hasOwnProperty(n));return i?i[n]=r:e[e.length-1][n]=r,!0}});return t}function F(e){let t=(n,r="")=>{Object.entries(Object.getOwnPropertyDescriptors(n)).forEach(([i,{value:o,enumerable:a}])=>{if(!1===a||void 0===o)return;let s=""===r?i:`${r}.${i}`;var l;"object"==typeof o&&null!==o&&o._x_interceptor?n[i]=o.initialize(e,s,i):"object"!=typeof(l=o)||Array.isArray(l)||null===l||o===n||o instanceof Element||t(o,s)})};return t(e)}function B(e,t=(()=>{})){let n={initialValue:void 0,_x_interceptor:!0,initialize(t,n,r){return e(this.initialValue,()=>function(e,t){return t.split(".").reduce((e,t)=>e[t],e)}(t,n),e=>q(t,n,e),n,r)}};return t(n),e=>{if("object"==typeof e&&null!==e&&e._x_interceptor){let t=n.initialize.bind(n);n.initialize=(r,i,o)=>{let a=e.initialize(r,i,o);return n.initialValue=a,t(r,i,o)}}else n.initialValue=e;return n}}function q(e,t,n){if("string"==typeof t&&(t=t.split(".")),1!==t.length){if(0===t.length)throw error;return e[t[0]]||(e[t[0]]={}),q(e[t[0]],t.slice(1),n)}e[t[0]]=n}var V={};function W(e,t){V[e]=t}function U(e,t){return Object.entries(V).forEach(([n,r])=>{Object.defineProperty(e,`$${n}`,{get:()=>r(t,{Alpine:et,interceptor:B}),enumerable:!1})}),e}function K(e,t,n,...r){try{return n(...r)}catch(n){G(n,e,t)}}function G(e,t,n){Object.assign(e,{el:t,expression:n}),console.warn(`Alpine Expression Error: ${e.message}\n\n${n?'Expression: "'+n+'"\n\n':""}`,t),setTimeout(()=>{throw e},0)}function Y(e,t,n={}){let r;return H(e,t)(e=>r=e,n),r}function H(...e){return J(...e)}var J=Z;function Z(e,t){let n={};U(n,e);let r=[n,...z(e)];if("function"==typeof t)return function(e,t){return(n=(()=>{}),{scope:r={},params:i=[]}={})=>{Q(n,t.apply(D([r,...e]),i))}}(r,t);let i=function(e,t,n){let r=function(e,t){if(X[e])return X[e];let n=Object.getPrototypeOf(async function(){}).constructor,r=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e,i=(()=>{try{return new n(["__self","scope"],`with (scope) { __self.result = ${r} }; __self.finished = true; return __self.result;`)}catch(n){return G(n,t,e),Promise.resolve()}})();return X[e]=i,i}(t,n);return(i=(()=>{}),{scope:o={},params:a=[]}={})=>{r.result=void 0,r.finished=!1;let s=D([o,...e]);if("function"==typeof r){let e=r(r,s).catch(e=>G(e,n,t));r.finished?(Q(i,r.result,s,a,n),r.result=void 0):e.then(e=>{Q(i,e,s,a,n)}).catch(e=>G(e,n,t)).finally(()=>r.result=void 0)}}}(r,t,e);return K.bind(null,e,t,i)}var X={};function Q(e,t,n,r,i){if("function"==typeof t){let o=t.apply(n,r);o instanceof Promise?o.then(t=>Q(e,t,n,r)).catch(e=>G(e,i,t)):e(o)}else e(t)}var ee="x-";function te(e=""){return ee+e}var ne={};function re(e,t){ne[e]=t}function ie(e,r,i){let o={};return Array.from(r).map(ce((e,t)=>o[e]=t)).filter(de).map(function(e,t){return({name:n,value:r})=>{let i=n.match(pe()),o=n.match(/:([a-zA-Z0-9\-:]+)/),a=n.match(/\.[^.\]]+(?=[^\]]*$)/g)||[],s=t||e[n]||n;return{type:i?i[1]:null,value:o?o[1]:null,modifiers:a.map(e=>e.replace(".","")),expression:r,original:s}}}(o,i)).sort(ge).map(r=>function(e,r){let i=ne[r.type]||(()=>{}),o=[],[a,s]=function(e){let r=()=>{};return[i=>{let o=t(i);e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(e=>e())}),e._x_effects.add(o),r=()=>{void 0!==o&&(e._x_effects.delete(o),n(o))}},()=>{r()}]}(e);o.push(s);let l={Alpine:et,effect:a,cleanup:e=>o.push(e),evaluateLater:H.bind(H,e),evaluate:Y.bind(Y,e)},c=()=>o.forEach(e=>e());!function(e,t,n){e._x_attributeCleanups||(e._x_attributeCleanups={}),e._x_attributeCleanups[t]||(e._x_attributeCleanups[t]=[]),e._x_attributeCleanups[t].push(n)}(e,r.original,c);let u=()=>{e._x_ignore||e._x_ignoreSelf||(i.inline&&i.inline(e,r,l),i=i.bind(i,e,r,l),oe?ae.get(se).push(i):i())};return u.runCleanups=c,u}(e,r))}var oe=!1,ae=new Map,se=Symbol(),le=(e,t)=>({name:n,value:r})=>(n.startsWith(e)&&(n=n.replace(e,t)),{name:n,value:r});function ce(e=(()=>{})){return({name:t,value:n})=>{let{name:r,value:i}=ue.reduce((e,t)=>t(e),{name:t,value:n});return r!==t&&e(r,t),{name:r,value:i}}}var ue=[];function fe(e){ue.push(e)}function de({name:e}){return pe().test(e)}var pe=()=>new RegExp(`^${ee}([^:^.]+)\\b`),he="DEFAULT",_e=["ignore","ref","data","id","bind","init","for","model","modelable","transition","show","if",he,"teleport","element"];function ge(e,t){let n=-1===_e.indexOf(e.type)?he:e.type,r=-1===_e.indexOf(t.type)?he:t.type;return _e.indexOf(n)-_e.indexOf(r)}function me(e,t,n={}){e.dispatchEvent(new CustomEvent(t,{detail:n,bubbles:!0,composed:!0,cancelable:!0}))}var ye=[],ve=!1;function be(e){ye.push(e),queueMicrotask(()=>{ve||setTimeout(()=>{xe()})})}function xe(){for(ve=!1;ye.length;)ye.shift()()}function we(e,t){if("function"==typeof ShadowRoot&&e instanceof ShadowRoot)return void Array.from(e.children).forEach(e=>we(e,t));let n=!1;if(t(e,()=>n=!0),n)return;let r=e.firstElementChild;for(;r;)we(r,t),r=r.nextElementSibling}function Oe(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var Ee=[],ke=[];function Se(){return Ee.map(e=>e())}function Ae(){return Ee.concat(ke).map(e=>e())}function je(e){Ee.push(e)}function Ce(e){ke.push(e)}function Re(e,t=!1){return Me(e,e=>{if((t?Ae():Se()).some(t=>e.matches(t)))return!0})}function Me(e,t){if(e){if(t(e))return e;if(e._x_teleportBack&&(e=e._x_teleportBack),e.parentElement)return Me(e.parentElement,t)}}function Te(e,t=we){!function(n){oe=!0;let r=Symbol();se=r,ae.set(r,[]),t(e,(e,t)=>{ie(e,e.attributes).forEach(e=>e()),e._x_ignore&&t()}),oe=!1,(()=>{for(;ae.get(r).length;)ae.get(r).shift()();ae.delete(r)})()}()}function Pe(e,t){return Array.isArray(t)?Ne(e,t.join(" ")):"object"==typeof t&&null!==t?function(e,t){let n=e=>e.split(" ").filter(Boolean),r=Object.entries(t).flatMap(([e,t])=>!!t&&n(e)).filter(Boolean),i=Object.entries(t).flatMap(([e,t])=>!t&&n(e)).filter(Boolean),o=[],a=[];return i.forEach(t=>{e.classList.contains(t)&&(e.classList.remove(t),a.push(t))}),r.forEach(t=>{e.classList.contains(t)||(e.classList.add(t),o.push(t))}),()=>{a.forEach(t=>e.classList.add(t)),o.forEach(t=>e.classList.remove(t))}}(e,t):"function"==typeof t?Pe(e,t()):Ne(e,t)}function Ne(e,t){return t=!0===t?t="":t||"",n=t.split(" ").filter(t=>!e.classList.contains(t)).filter(Boolean),e.classList.add(...n),()=>{e.classList.remove(...n)};var n}function $e(e,t){return"object"==typeof t&&null!==t?function(e,t){let n={};return Object.entries(t).forEach(([t,r])=>{n[t]=e.style[t],t.startsWith("--")||(t=t.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()),e.style.setProperty(t,r)}),setTimeout(()=>{0===e.style.length&&e.removeAttribute("style")}),()=>{$e(e,n)}}(e,t):function(e,t){let n=e.getAttribute("style",t);return e.setAttribute("style",t),()=>{e.setAttribute("style",n||"")}}(e,t)}function Le(e,t=(()=>{})){let n=!1;return function(){n?t.apply(this,arguments):(n=!0,e.apply(this,arguments))}}function Ie(e,t,n={}){e._x_transition||(e._x_transition={enter:{during:n,start:n,end:n},leave:{during:n,start:n,end:n},in(n=(()=>{}),r=(()=>{})){De(e,t,{during:this.enter.during,start:this.enter.start,end:this.enter.end},n,r)},out(n=(()=>{}),r=(()=>{})){De(e,t,{during:this.leave.during,start:this.leave.start,end:this.leave.end},n,r)}})}function ze(e){let t=e.parentNode;if(t)return t._x_hidePromise?t:ze(t)}function De(e,t,{during:n,start:r,end:i}={},o=(()=>{}),a=(()=>{})){if(e._x_transitioning&&e._x_transitioning.cancel(),0===Object.keys(n).length&&0===Object.keys(r).length&&0===Object.keys(i).length)return o(),void a();let s,l,c;!function(e,t){let n,r,i,o=Le(()=>{M(()=>{n=!0,r||t.before(),i||(t.end(),xe()),t.after(),e.isConnected&&t.cleanup(),delete e._x_transitioning})});e._x_transitioning={beforeCancels:[],beforeCancel(e){this.beforeCancels.push(e)},cancel:Le(function(){for(;this.beforeCancels.length;)this.beforeCancels.shift()();o()}),finish:o},M(()=>{t.start(),t.during()}),ve=!0,requestAnimationFrame(()=>{if(n)return;let o=1e3*Number(getComputedStyle(e).transitionDuration.replace(/,.*/,"").replace("s","")),a=1e3*Number(getComputedStyle(e).transitionDelay.replace(/,.*/,"").replace("s",""));0===o&&(o=1e3*Number(getComputedStyle(e).animationDuration.replace("s",""))),M(()=>{t.before()}),r=!0,requestAnimationFrame(()=>{n||(M(()=>{t.end()}),xe(),setTimeout(e._x_transitioning.finish,o+a),i=!0)})})}(e,{start(){s=t(e,r)},during(){l=t(e,n)},before:o,end(){s(),c=t(e,i)},after:a,cleanup(){l(),c()}})}function Fe(e,t,n){if(-1===e.indexOf(t))return n;const r=e[e.indexOf(t)+1];if(!r)return n;if("scale"===t&&isNaN(r))return n;if("duration"===t){let e=r.match(/([0-9]+)ms/);if(e)return e[1]}return"origin"===t&&["top","right","left","center","bottom"].includes(e[e.indexOf(t)+2])?[r,e[e.indexOf(t)+2]].join(" "):r}re("transition",(e,{value:t,modifiers:n,expression:r},{evaluate:i})=>{"function"==typeof r&&(r=i(r)),r?function(e,t,n){Ie(e,Pe,""),{enter:t=>{e._x_transition.enter.during=t},"enter-start":t=>{e._x_transition.enter.start=t},"enter-end":t=>{e._x_transition.enter.end=t},leave:t=>{e._x_transition.leave.during=t},"leave-start":t=>{e._x_transition.leave.start=t},"leave-end":t=>{e._x_transition.leave.end=t}}[n](t)}(e,r,t):function(e,t,n){Ie(e,$e);let r=!t.includes("in")&&!t.includes("out")&&!n,i=r||t.includes("in")||["enter"].includes(n),o=r||t.includes("out")||["leave"].includes(n);t.includes("in")&&!r&&(t=t.filter((e,n)=>nn>t.indexOf("out")));let a=!t.includes("opacity")&&!t.includes("scale"),s=a||t.includes("opacity")?0:1,l=a||t.includes("scale")?Fe(t,"scale",95)/100:1,c=Fe(t,"delay",0),u=Fe(t,"origin","center"),f="opacity, transform",d=Fe(t,"duration",150)/1e3,p=Fe(t,"duration",75)/1e3,h="cubic-bezier(0.4, 0.0, 0.2, 1)";i&&(e._x_transition.enter.during={transformOrigin:u,transitionDelay:c,transitionProperty:f,transitionDuration:`${d}s`,transitionTimingFunction:h},e._x_transition.enter.start={opacity:s,transform:`scale(${l})`},e._x_transition.enter.end={opacity:1,transform:"scale(1)"}),o&&(e._x_transition.leave.during={transformOrigin:u,transitionDelay:c,transitionProperty:f,transitionDuration:`${p}s`,transitionTimingFunction:h},e._x_transition.leave.start={opacity:1,transform:"scale(1)"},e._x_transition.leave.end={opacity:s,transform:`scale(${l})`})}(e,n,t)}),window.Element.prototype._x_toggleAndCascadeWithTransitions=function(e,t,n,r){let i=()=>{"visible"===document.visibilityState?requestAnimationFrame(n):setTimeout(n)};t?e._x_transition&&(e._x_transition.enter||e._x_transition.leave)?e._x_transition.enter&&(Object.entries(e._x_transition.enter.during).length||Object.entries(e._x_transition.enter.start).length||Object.entries(e._x_transition.enter.end).length)?e._x_transition.in(n):i():e._x_transition?e._x_transition.in(n):i():(e._x_hidePromise=e._x_transition?new Promise((t,n)=>{e._x_transition.out(()=>{},()=>t(r)),e._x_transitioning.beforeCancel(()=>n({isFromCancelledTransition:!0}))}):Promise.resolve(r),queueMicrotask(()=>{let t=ze(e);t?(t._x_hideChildren||(t._x_hideChildren=[]),t._x_hideChildren.push(e)):queueMicrotask(()=>{let t=e=>{let n=Promise.all([e._x_hidePromise,...(e._x_hideChildren||[]).map(t)]).then(([e])=>e());return delete e._x_hidePromise,delete e._x_hideChildren,n};t(e).catch(e=>{if(!e.isFromCancelledTransition)throw e})})}))};var Be=!1;function qe(e,t=(()=>{})){return(...n)=>Be?t(...n):e(...n)}function Ve(t,n,r,i=[]){switch(t._x_bindings||(t._x_bindings=e({})),t._x_bindings[n]=r,n=i.includes("camel")?n.toLowerCase().replace(/-(\w)/g,(e,t)=>t.toUpperCase()):n){case"value":!function(e,t){if("radio"===e.type)void 0===e.attributes.value&&(e.value=t),window.fromModel&&(e.checked=We(e.value,t));else if("checkbox"===e.type)Number.isInteger(t)?e.value=t:Number.isInteger(t)||Array.isArray(t)||"boolean"==typeof t||[null,void 0].includes(t)?e.checked=Array.isArray(t)?t.some(t=>We(t,e.value)):!!t:e.value=String(t);else if("SELECT"===e.tagName)!function(e,t){const n=[].concat(t).map(e=>e+"");Array.from(e.options).forEach(e=>{e.selected=n.includes(e.value)})}(e,t);else{if(e.value===t)return;e.value=t}}(t,r);break;case"style":!function(e,t){e._x_undoAddedStyles&&e._x_undoAddedStyles(),e._x_undoAddedStyles=$e(e,t)}(t,r);break;case"class":!function(e,t){e._x_undoAddedClasses&&e._x_undoAddedClasses(),e._x_undoAddedClasses=Pe(e,t)}(t,r);break;default:!function(e,t,n){[null,void 0,!1].includes(n)&&function(e){return!["aria-pressed","aria-checked","aria-expanded","aria-selected"].includes(e)}(t)?e.removeAttribute(t):(Ue(t)&&(n=t),function(e,t,n){e.getAttribute(t)!=n&&e.setAttribute(t,n)}(e,t,n))}(t,n,r)}}function We(e,t){return e==t}function Ue(e){return["disabled","checked","required","readonly","hidden","open","selected","autofocus","itemscope","multiple","novalidate","allowfullscreen","allowpaymentrequest","formnovalidate","autoplay","controls","loop","muted","playsinline","default","ismap","reversed","async","defer","nomodule"].includes(e)}function Ke(e,t){var n;return function(){var r=this,i=arguments,o=function(){n=null,e.apply(r,i)};clearTimeout(n),n=setTimeout(o,t)}}function Ge(e,t){let n;return function(){let r=this,i=arguments;n||(e.apply(r,i),n=!0,setTimeout(()=>n=!1,t))}}var Ye,He,Je={},Ze=!1,Xe={},Qe={},et={get reactive(){return e},get release(){return n},get effect(){return t},get raw(){return r},version:"3.9.0",flushAndStopDeferringMutations:function(){T=!1,N(P),P=[]},disableEffectScheduling:function(e){b=!1,e(),b=!0},setReactivityEngine:function(i){e=i.reactive,n=i.release,t=e=>i.effect(e,{scheduler:e=>{b?function(e){var t;m.includes(t=e)||m.push(t),g||_||(_=!0,queueMicrotask(v))}(e):e()}}),r=i.raw},closestDataStack:z,skipDuringClone:qe,addRootSelector:je,addInitSelector:Ce,addScopeToNode:L,deferMutations:function(){T=!0},mapAttributes:fe,evaluateLater:H,setEvaluator:function(e){J=e},mergeProxies:D,findClosest:Me,closestRoot:Re,interceptor:B,transition:De,setStyles:$e,mutateDom:M,directive:re,throttle:Ge,debounce:Ke,evaluate:Y,initTree:Te,nextTick:be,prefixed:te,prefix:function(e){ee=e},plugin:function(e){e(et)},magic:W,store:function(t,n){if(Ze||(Je=e(Je),Ze=!0),void 0===n)return Je[t];Je[t]=n,"object"==typeof n&&null!==n&&n.hasOwnProperty("init")&&"function"==typeof n.init&&Je[t].init(),F(Je[t])},start:function(){document.body||Oe("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's `'); 62 | } 63 | 64 | protected function buildConfig(array $config) 65 | { 66 | $config['indexName'] = $this->indexName($config['indexName']); 67 | 68 | $this->config = Js::from(collect($config)->filter()); 69 | } 70 | 71 | protected function indexName($input): string 72 | { 73 | if ($this->isSearchableModelClassName($input)) { 74 | $input = new $input(); 75 | } 76 | 77 | if (method_exists($input, 'searchableAs')) { 78 | $input = $input->searchableAs(); 79 | } 80 | 81 | return (string) $input; 82 | } 83 | 84 | protected function isSearchableModelClassName($input): bool 85 | { 86 | return class_exists($input) 87 | && is_subclass_of($input, Model::class, true) 88 | && method_exists($input, 'searchableAs'); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Components/Menu.php: -------------------------------------------------------------------------------- 1 | setId($id); 15 | $this->setWidgetData(array_filter(compact( 16 | 'attribute', 17 | 'limit', 18 | 'showMore', 19 | 'showMoreLimit' 20 | ))); 21 | } 22 | 23 | public function render() 24 | { 25 | return view('instantsearch::menu'); 26 | } 27 | 28 | protected function widgetDefaults(): string 29 | { 30 | return '{ items: [], canRefine: false, isShowingMore: false, canToggleShowMore: false, refine: null, sendEvent: null, createURL: null, toggleShowMore: null, widgetParams: {} }'; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Components/MenuSelect.php: -------------------------------------------------------------------------------- 1 | setId($id); 13 | $this->setWidgetData(array_filter(compact( 14 | 'attribute', 15 | 'limit' 16 | ))); 17 | } 18 | 19 | public function render() 20 | { 21 | return view('instantsearch::menu-select'); 22 | } 23 | 24 | protected function widgetDefaults(): string 25 | { 26 | return '{ items: [], canRefine: false, refine: null, sendEvent: null, widgetParams: {} }'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Components/NumericMenu.php: -------------------------------------------------------------------------------- 1 | setWidgetData(array_filter(compact( 12 | 'attribute', 13 | 'items' 14 | ))); 15 | } 16 | 17 | public function render() 18 | { 19 | return view('instantsearch::numeric-menu'); 20 | } 21 | 22 | protected function widgetDefaults(): string 23 | { 24 | return '{ items: [], hasNoResults: true, refine: null, sendEvent: null, createURL: null, widgetParams: {} }'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Components/Pagination.php: -------------------------------------------------------------------------------- 1 | setWidgetData(array_filter(compact( 17 | 'showFirst', 18 | 'showPrevious', 19 | 'showNext', 20 | 'showLast', 21 | 'padding', 22 | 'totalPages' 23 | ))); 24 | } 25 | 26 | public function render() 27 | { 28 | return view('instantsearch::pagination'); 29 | } 30 | 31 | protected function widgetDefaults(): string 32 | { 33 | return '{ pages: [], currentRefinement: 0, nbHits: 0, nbPages: 0, isFirstPage: true, isLastPage: false, canRefine: false, refine: null, createURL: null, widgetParams: null }'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Components/RangeInput.php: -------------------------------------------------------------------------------- 1 | setId($id); 15 | $this->setWidgetData(array_filter(compact( 16 | 'attribute', 17 | 'min', 18 | 'max', 19 | 'precision' 20 | ))); 21 | } 22 | 23 | public function render() 24 | { 25 | return view('instantsearch::range-input'); 26 | } 27 | 28 | protected function widgetDefaults(): string 29 | { 30 | return '{ start: [], range: {}, canRefine: false, refine: null, sendEvent: null, widgetParams: {} }'; 31 | } 32 | 33 | protected function widgetName(): string 34 | { 35 | return 'Range'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Components/RangeSlider.php: -------------------------------------------------------------------------------- 1 | setId($id); 17 | $this->setWidgetData(array_filter(compact( 18 | 'attribute', 19 | 'min', 20 | 'max', 21 | 'precision', 22 | 'step', 23 | 'pips' 24 | ))); 25 | } 26 | 27 | public function render() 28 | { 29 | return view('instantsearch::range-slider'); 30 | } 31 | 32 | protected function widgetDefaults(): string 33 | { 34 | return '{ start: [], range: {}, canRefine: false, refine: null, sendEvent: null, widgetParams: {} }'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Components/RatingMenu.php: -------------------------------------------------------------------------------- 1 | setId($id); 13 | $this->setWidgetData(array_filter(compact( 14 | 'attribute', 15 | 'max' 16 | ))); 17 | } 18 | 19 | public function render() 20 | { 21 | return view('instantsearch::rating-menu'); 22 | } 23 | 24 | protected function widgetDefaults(): string 25 | { 26 | return '{ items: [], hasNoResults: true, canRefine: false, refine: null, sendEvent: null, createURL: null, widgetParams: {} }'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Components/Refinement.php: -------------------------------------------------------------------------------- 1 | id = $id ?? Str::random(); 31 | $this->show_more = $showMore; 32 | $this->searchable = $searchable; 33 | $this->searchable_placeholder = $searchablePlaceholder ?? 'Search…'; 34 | 35 | $this->setWidgetData(array_filter(compact( 36 | 'id', 37 | 'attribute', 38 | 'operator', 39 | 'limit', 40 | 'showMore', 41 | 'showMoreLimit', 42 | 'searchable', 43 | 'searchablePlaceholder', 44 | 'searchableIsAlwaysActive', 45 | 'searchableEscapeFacetValues', 46 | 'sortBy' 47 | ))); 48 | } 49 | 50 | public function render() 51 | { 52 | return view('instantsearch::refinement-list'); 53 | } 54 | 55 | protected function widgetDefaults(): string 56 | { 57 | return '{ items: [], canRefine: false, refine: null, sendEvent: null, createURL: null, isFromSearch: false, searchForItems: null, isShowingMore: false, canToggleShowMore: false, toggleShowMore: null, widgetParams: {} }'; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Components/SearchBox.php: -------------------------------------------------------------------------------- 1 | setWidgetData(array_filter(compact( 14 | 'searchAsYouType', 15 | 'showReset', 16 | 'showSubmit', 17 | 'showLoadingIndicator' 18 | ))); 19 | } 20 | 21 | public function render() 22 | { 23 | return view('instantsearch::search-box'); 24 | } 25 | 26 | protected function widgetDefaults(): string 27 | { 28 | return "{ query: '', refine: null, clear: null, isSearchStalled: false, widgetParams: {} }"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Components/Snippet.php: -------------------------------------------------------------------------------- 1 | attribute = $attribute; 18 | $this->highlightedTagName = $highlightedTagName; 19 | $this->tagName = $tagName; 20 | } 21 | 22 | public function render() 23 | { 24 | return view('instantsearch::snippet'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Components/SortBy.php: -------------------------------------------------------------------------------- 1 | setId($id); 11 | } 12 | 13 | public function render() 14 | { 15 | return view('instantsearch::sort-by'); 16 | } 17 | 18 | protected function widgetDefaults(): string 19 | { 20 | return '{ options: [], currentRefinement: \'\', hasNoResults: false, refine: null, widgetParams: {} }'; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Components/ToggleRefinement.php: -------------------------------------------------------------------------------- 1 | setId($id); 12 | $this->setWidgetData(array_filter(compact( 13 | 'attribute' 14 | ))); 15 | } 16 | 17 | public function render() 18 | { 19 | return view('instantsearch::toggle-refinement'); 20 | } 21 | 22 | protected function widgetDefaults(): string 23 | { 24 | return '{ value: {}, canRefine: false, refine: null, sendEvent: null, createURL: null, widgetParams: {} }'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Components/Widget.php: -------------------------------------------------------------------------------- 1 | isRenderless() 19 | ? view('instantsearch::connected-component') 20 | : $this->render(); 21 | 22 | return $view->with($data); 23 | }; 24 | } 25 | 26 | public function render() 27 | { 28 | return view('instantsearch::connected-component'); 29 | } 30 | 31 | public function withAttributes(array $attributes) 32 | { 33 | $name = $this->widgetName(); 34 | $config = Js::from($this->widget_config); 35 | $defaults = $this->widgetDefaults(); 36 | 37 | $attributes = array_merge($attributes, [ 38 | 'x-data' => new HtmlString("BladeAlpineInstantSearch.widget(\$el, '{$name}', {$config}, {$defaults})"), 39 | ]); 40 | 41 | return parent::withAttributes($attributes); 42 | } 43 | 44 | public function setId($id) 45 | { 46 | $this->id = $id ?? Str::random(); 47 | 48 | return $this; 49 | } 50 | 51 | protected function setWidgetData(array $data) 52 | { 53 | $this->widget_config = $data; 54 | } 55 | 56 | protected function widgetDefaults(): string 57 | { 58 | return '{}'; 59 | } 60 | 61 | protected function widgetName(): string 62 | { 63 | return class_basename($this); 64 | } 65 | 66 | protected function isRenderless(): bool 67 | { 68 | return $this->renderlessAttribute() ?? config('instantsearch.renderless', false); 69 | } 70 | 71 | protected function renderlessAttribute(): ?bool 72 | { 73 | if (! ($this->attributes instanceof ComponentAttributeBag)) { 74 | return null; 75 | } 76 | 77 | if (! $this->attributes->has('renderless')) { 78 | return null; 79 | } 80 | 81 | return (bool) $this->attributes->get('renderless'); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Facades/BladeInstantSearch.php: -------------------------------------------------------------------------------- 1 | helper = new BladeInstantSearch(); 35 | $this->app->instance(BladeInstantSearch::class, $this->helper); 36 | 37 | $this->mergeConfigFrom($this->helper->path('config.php'), 'instantsearch'); 38 | } 39 | 40 | public function boot() 41 | { 42 | $this->publishes([ 43 | $this->helper->path('config.php') => config_path('instantsearch.php'), 44 | $this->helper->path('resources/views') => resource_path('views/vendor/instantsearch'), 45 | ], ['instantsearch']); 46 | 47 | $this->loadViewsFrom($this->helper->path('resources/views'), 'instantsearch'); 48 | 49 | $this->callAfterResolving(BladeCompiler::class, function(BladeCompiler $blade) { 50 | $blade->component(InstantSearch::class, 'instantsearch'); 51 | }); 52 | 53 | Blade::componentNamespace('InterNACHI\\BladeInstantSearch\\Components', 'instantsearch'); 54 | 55 | // $this->loadViewComponentsAs('instantsearch', [ 56 | // Breadcrumb::class, 57 | // ClearRefinements::class, 58 | // CurrentRefinements::class, 59 | // HierarchicalMenu::class, 60 | // Highlight::class, 61 | // Hit::class, 62 | // Hits::class, 63 | // Menu::class, 64 | // MenuSelect::class, 65 | // NumericMenu::class, 66 | // Pagination::class, 67 | // RangeSlider::class, 68 | // RatingMenu::class, 69 | // RefinementList::class, 70 | // SearchBox::class, 71 | // SortBy::class, 72 | // ToggleRefinement::class, 73 | // ]); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InterNACHI/blade-alpine-instantsearch/3e5a6cfd8dbffd4132eff1e19cc5cdd439bf84a1/tests/.gitkeep -------------------------------------------------------------------------------- /tests/Feature/ComponentRenderingTest.php: -------------------------------------------------------------------------------- 1 | Str::random(), 15 | 'searchKey' => Str::random(), 16 | 'indexName' => Str::random(), 17 | ]; 18 | 19 | $result = $this->blade(<<<'BLADE' 20 | 25 | BLADE, ['expected_payload' => $expected_payload]); 26 | 27 | $result->assertSee('x-data="BladeAlpineInstantSearch($el', false); 28 | $result->assertSee(Js::from($expected_payload), false); 29 | $result->assertSee('var BladeAlpineInstantSearch', false); 30 | } 31 | 32 | public function test_it_renders_breadcrumbs(): void 33 | { 34 | $result = $this->blade(''); 35 | 36 | $result->assertSee('x-data="BladeAlpineInstantSearch.widget($el, \'Breadcrumb\'', false); 37 | $result->assertSee('items:', false); 38 | $result->assertSee('canRefine:', false); 39 | $result->assertSee('refine:', false); 40 | $result->assertSee('createURL:', false); 41 | $result->assertSee('widgetParams:', false); 42 | } 43 | 44 | public function test_it_renders_clear_refinements(): void 45 | { 46 | $result = $this->blade(''); 47 | 48 | $result->assertSee('x-data="BladeAlpineInstantSearch.widget($el, \'ClearRefinements\'', false); 49 | $result->assertSee('canRefine:', false); 50 | $result->assertSee('refine:', false); 51 | $result->assertSee('createURL:', false); 52 | $result->assertSee('widgetParams:', false); 53 | } 54 | 55 | public function test_it_renders_current_refinements(): void 56 | { 57 | $result = $this->blade(''); 58 | 59 | $result->assertSee('x-data="BladeAlpineInstantSearch.widget($el, \'CurrentRefinements\'', false); 60 | $result->assertSee('items:', false); 61 | $result->assertSee('canRefine:', false); 62 | $result->assertSee('refine:', false); 63 | $result->assertSee('createURL:', false); 64 | $result->assertSee('widgetParams:', false); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | BladeInstantSearchFacade::class, 25 | ]; 26 | } 27 | } 28 | --------------------------------------------------------------------------------