├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .replit ├── .standard.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gemfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app ├── assets │ └── javascripts │ │ ├── turbo_stream_button.js │ │ └── turbo_stream_button │ │ └── turbo_stream_button │ │ ├── index.d.ts │ │ ├── index.d.ts.map │ │ ├── turbo_stream_button_controller.d.ts │ │ └── turbo_stream_button_controller.d.ts.map └── views │ └── application │ └── _turbo_stream_button.html.erb ├── bin └── rails ├── lib ├── tasks │ └── turbo_stream_button_tasks.rake ├── turbo_stream_button.rb └── turbo_stream_button │ ├── builder.rb │ ├── button.rb │ ├── engine.rb │ ├── helpers.rb │ ├── html.rb │ └── version.rb ├── package.json ├── packages └── turbo_stream_button │ ├── index.ts │ └── turbo_stream_button_controller.ts ├── replit.nix ├── rollup.config.js ├── test ├── application_system_test_case.rb ├── dummy │ ├── Rakefile │ ├── app │ │ ├── assets │ │ │ ├── config │ │ │ │ └── manifest.js │ │ │ ├── images │ │ │ │ └── .keep │ │ │ └── stylesheets │ │ │ │ └── application.css │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ └── examples_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── models │ │ │ └── concerns │ │ │ │ └── .keep │ │ └── views │ │ │ ├── examples │ │ │ └── index.html.erb │ │ │ └── layouts │ │ │ └── application.html.erb │ ├── bin │ │ ├── rails │ │ ├── rake │ │ └── setup │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── content_security_policy.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── permissions_policy.rb │ │ │ └── replit.rb │ │ ├── locales │ │ │ └── en.yml │ │ ├── puma.rb │ │ └── routes.rb │ ├── lib │ │ └── assets │ │ │ └── .keep │ ├── log │ │ └── .keep │ └── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ └── favicon.ico ├── integration │ └── examples_test.rb ├── system │ └── integration_test.rb ├── test_helper.rb └── turbo_stream_button_test.rb ├── tsconfig.json ├── turbo_stream_button.gemspec └── yarn.lock /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI Tests" 2 | 3 | on: 4 | - "pull_request" 5 | 6 | jobs: 7 | test: 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | ruby-version: 12 | - "3.1" 13 | - "3.2" 14 | - "3.3" 15 | rails-version: 16 | - "7.1" 17 | - "7.2" 18 | include: 19 | - { ruby-version: "3.2", rails-version: "main" } 20 | - { ruby-version: "3.3", rails-version: "main" } 21 | 22 | env: 23 | RAILS_VERSION: ${{ matrix.rails-version }} 24 | 25 | name: ${{ format('Tests (Ruby {0}, Rails {1})', matrix.ruby-version, matrix.rails-version) }} 26 | runs-on: "ubuntu-latest" 27 | 28 | steps: 29 | - uses: "actions/checkout@v2" 30 | - uses: "actions/setup-node@v2" 31 | with: 32 | node-version: "14" 33 | - uses: "ruby/setup-ruby@v1" 34 | with: 35 | rubygems: 3.3.13 36 | ruby-version: ${{ matrix.ruby-version }} 37 | bundler-cache: true 38 | 39 | - run: bin/rails standard 40 | - run: yarn install 41 | - run: yarn build 42 | - run: bin/rails test:all 43 | 44 | - name: Fail when generated changes are not checked-in 45 | run: | 46 | git update-index --refresh 47 | git diff-index --quiet HEAD -- 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /doc/ 3 | /log/*.log 4 | /pkg/ 5 | /tmp/ 6 | /test/dummy/log/*.log 7 | /test/dummy/tmp/ 8 | Gemfile.lock 9 | -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | entrypoint = "README.md" 2 | hidden = [".bundle"] 3 | 4 | run = "cd /home/runner/${REPL_SLUG}/test/dummy && bundle exec rails server --binding=0.0.0.0" 5 | 6 | [env] 7 | PATH = "/home/runner/${REPL_SLUG}/bin" 8 | 9 | [packager] 10 | language = "ruby" 11 | 12 | [packager.features] 13 | packageSearch = true 14 | guessImports = true 15 | 16 | [languages.ruby] 17 | pattern = "**/*.rb" 18 | 19 | [languages.ruby.languageServer] 20 | start = ["solargraph", "stdio"] 21 | 22 | [nix] 23 | channel = "unstable" 24 | -------------------------------------------------------------------------------- /.standard.yml: -------------------------------------------------------------------------------- 1 | ruby_version: 3.1 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | - Drop [end-of-life Ruby] versions 2.7 and 3.0 11 | - Drop [end-of-life Rails] versions 6.2 and 7.0 12 | 13 | [end-of-life Ruby]: https://www.ruby-lang.org/en/downloads/branches/ 14 | [end-of-lie Rails]: https://rubyonrails.org/maintenance 15 | 16 | ## 0.2.3 (Oct 24, 2024) 17 | 18 | - Expand matrix of supported versions to include `ruby@3.3` and `rails@7.2`. 19 | - Rely on view context's `#token_list` to merge token lists 20 | 21 | ## 0.2.2 (Jan 12, 2023) 22 | 23 | - Qualify call to `render "turbo_stream_button_tag"` with `application/` 24 | namespace 25 | 26 | ## 0.2.1 (Jan 12, 2023) 27 | 28 | - Introduce `turbo_stream_button` and `turbo_stream_button.template` helpers 29 | that know how to render themselves as attributes or elements 30 | 31 | form_with model: Post.new do |form| 32 | form.button **turbo_stream_button, type: :submit do 33 | turbo_stream_button.template.tag do 34 | turbo_stream.append(...) 35 | end 36 | end 37 | end 38 | 39 | ### Fixed 40 | 41 | - Support multiple tokens in token list mergers 42 | - Resolve `TurboStreamButton::Helpers` loading issue 43 | 44 | ## 0.2.0 (Jun 30, 2022 ) 45 | 46 | ### Changed 47 | 48 | - Replace checks for `nice_partials` with built-in support for capturing the 49 | `turbo_streams` block 50 | 51 | ### Added 52 | 53 | - Introduce the `turbo_stream_button_tag` helper, and replace documented calls 54 | to `render("turbo_stream_button")` with calls to `turbo_stream_button_tag` 55 | 56 | ## 0.1.0 57 | 58 | - Initial release 59 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of conduct 2 | 3 | By participating in this project, you agree to abide by the 4 | [thoughtbot code of conduct][1]. 5 | 6 | [1]: https://thoughtbot.com/open-source-code-of-conduct 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `turbo_stream_button` 2 | 3 | We love pull requests from everyone. By participating in this project, you 4 | agree to abide by the thoughtbot [code of conduct][]. 5 | 6 | [code of conduct]: https://thoughtbot.com/open-source-code-of-conduct 7 | 8 | Here are some ways *you* can contribute: 9 | 10 | * by using alpha, beta, and prerelease versions 11 | * by reporting bugs 12 | * by suggesting new features 13 | * by writing or editing documentation 14 | * by writing specifications 15 | * by writing code (**no patch is too small** : fix typos, add comments, etc.) 16 | * by refactoring code 17 | * by closing [issues][] 18 | * by reviewing patches 19 | 20 | [issues]: https://github.com/seanpdoyle/turbo_stream_button/issues 21 | 22 | ## Submitting an Issue 23 | 24 | * We use the [GitHub issue tracker][issues] to track bugs and features. 25 | * Before submitting a bug report or feature request, check to make sure it hasn't 26 | already been submitted. 27 | * When submitting a bug report, please include a [reproduction script] and any 28 | other details that may be necessary to reproduce the bug, including your gem 29 | version, Ruby version, and operating system. 30 | 31 | ## Cleaning up issues 32 | 33 | * Issues that have no response from the submitter will be closed after 30 days. 34 | * Issues will be closed once they're assumed to be fixed or answered. If the 35 | maintainer is wrong, it can be opened again. 36 | * If your issue is closed by mistake, please understand and explain the issue. 37 | We will happily reopen the issue. 38 | 39 | ## Submitting a Pull Request 40 | 41 | 1. [Fork][fork] the [official repository][repo]. 42 | 1. [Create a topic branch.][branch] 43 | 1. Implement your feature or bug fix. 44 | 1. Add an entry to the [CHANGELOG.md](./CHANGELOG.md) 45 | 1. Add, commit, and push your changes. 46 | 1. [Submit a pull request.][pr] 47 | 48 | ### Notes 49 | 50 | * Please add tests if you changed code. Contributions without tests won't be accepted. 51 | * If you don't know how to add tests, please put in a PR and leave a comment 52 | asking for help. We love helping! 53 | * Please don't update the Gem version. 54 | 55 | ## Setting up 56 | 57 | ```sh 58 | bundle install 59 | yarn install 60 | ``` 61 | 62 | ## Running the test suite 63 | 64 | The default rake task will run the full test suite and [standard]: 65 | 66 | ```sh 67 | bin/rails test:all 68 | ``` 69 | 70 | You can also run a single group of tests (unit or system) 71 | 72 | ```sh 73 | bin/rails test 74 | bin/rails test:system 75 | ``` 76 | 77 | To run an individual test, you can provide a path and line number: 78 | 79 | ```sh 80 | bin/rails test/path/to/test.rb:123 81 | ``` 82 | 83 | You can run tests with a specific version of `rails` by setting the 84 | `RAILS_VERSION` environment variable, then executing `bundle install`: 85 | 86 | ```sh 87 | export RAILS_VERSION=7.0 88 | rm Gemfile.lock 89 | bundle install 90 | bin/rails test:all 91 | ``` 92 | 93 | To execute the test suite against `main`, set `RAILS_VERSION` to `main`: 94 | 95 | ```sh 96 | export RAILS_VERSION=main 97 | bundle install 98 | bin/rails test:all 99 | ``` 100 | 101 | ## Formatting 102 | 103 | Use [standard] to automatically format your code: 104 | 105 | ```sh 106 | bin/rails standard:fix 107 | ``` 108 | 109 | [repo]: https://github.com/seanpdoyle/turbo_stream_button/tree/main 110 | [fork]: https://help.github.com/articles/fork-a-repo/ 111 | [branch]: https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/ 112 | [pr]: https://help.github.com/articles/using-pull-requests/ 113 | [standard]: https://github.com/testdouble/standard 114 | 115 | Inspired by https://github.com/thoughtbot/factory_bot/blob/master/CONTRIBUTING.md 116 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | # Specify your gem's dependencies in turbo_stream_button.gemspec. 5 | gemspec 6 | 7 | # Start debugger with binding.b [https://github.com/ruby/debug] 8 | # gem "debug", ">= 1.0.0" 9 | 10 | rails_version = ENV.fetch("RAILS_VERSION", "7.2") 11 | 12 | rails_constraint = if rails_version == "main" 13 | {github: "rails/rails"} 14 | else 15 | "~> #{rails_version}.0" 16 | end 17 | 18 | gem "rails", rails_constraint 19 | gem "turbo-rails" 20 | gem "sprockets-rails" 21 | 22 | gem "puma" 23 | gem "rexml" 24 | gem "tzinfo-data" 25 | 26 | group :development, :test do 27 | gem "standard" unless ENV["REPL_SLUG"] 28 | end 29 | 30 | group :test do 31 | gem "action_dispatch-testing-integration-capybara", 32 | github: "thoughtbot/action_dispatch-testing-integration-capybara", tag: "v0.1.0", 33 | require: "action_dispatch/testing/integration/capybara/minitest" 34 | gem "capybara" 35 | gem "capybara_accessible_selectors", github: "citizensadvice/capybara_accessible_selectors", tag: "v0.10.0" 36 | gem "cuprite", require: "capybara/cuprite" 37 | end 38 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Sean Doyle 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ` 21 | ``` 22 | 23 | [Try it out.](https://jsfiddle.net/toybqx89/) 24 | 25 | [Turbo Streams]: https://turbo.hotwired.dev/reference/streams 26 | 27 | ## Usage 28 | 29 | In your JavaScript code, import and register the `turbo-stream-button` 30 | controller with your Stimulus application: 31 | 32 | ```javascript 33 | import "@hotwired/turbo" 34 | import { Application } from "stimulus" 35 | import { TurboStreamButtonController } from "@seanpdoyle/turbo_stream_button" 36 | 37 | const application = Application.start() 38 | application.register("turbo-stream-button", TurboStreamButtonController) 39 | ``` 40 | 41 | In your Rails templates, call the `turbo_stream_button_tag` helper or render the 42 | `turbo_stream_button` view partial to create the `