├── .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 |
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 |
--------------------------------------------------------------------------------