Skip to content

Improve readme #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 46 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@

This gem adds a simple way to automatically register custom elements in your `importmap-rails` app. No build step required!

## Table of Contents

<details>
<summary>Click to expand</summary>

- [Rails support](#rails-support)
- [Installation](#installation)
- [Generators](#generators)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [License](#license)

</details>

## Rails support

* Supports Rails 7.0, 7.1, 7.2 & 8.0
* Supports `importmap-rails` 1 and 2

## Installation

Add this line to your application's Gemfile:
Expand All @@ -14,74 +33,67 @@ gem "custom_elements-rails"

Install the gem:

```bash
```console
$ bundle install
```

Run the initial setup:

```bash
```console
$ rails custom_elements:install
```

This will setup and edit add the following files:

```
```graphql
app/javascript
├── application.js
└── custom_elements
├── hello_element.js
└── index.js
```

The `<app-hello>` custom element can be used in the views now.
The `<app-hello>` custom element can be used in views now.

You can generate a new custom element with `rails g custom_element abc`.
You can generate a new custom element `<app-demo>` with `rails generate custom_element demo`.

## How it works
### How It Works

The setup will add a JS function call `eagerDefineCustomElementsFrom` that parses the importmap rendered by the `importmap-rails` gem.
It registers custom elements with `customElements.define(...)` in the browser's registry based on the filenames in the `custom_elements` folder automatically.
The `custom_elements-rails` gem uses `eagerDefineCustomElementsFrom` to automatically register [custom elements](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements) in the `custom_elements` folder. It parses the importmap generated by `importmap-rails` and registers custom elements using the `customElements.define(...)` API.

```
custom_elements/hello_element.js // will register <app-hello> automatically
```

Your `*_element.js` files have to `export default` custom elements for this to work properly.
> [!IMPORTANT]
> Make sure your `*_element.js` files use `export default` to define the custom elements.

### Naming Convention for Custom Elements

When defining custom elements from files, their filenames are used to generate the element names automatically. The following rules and examples clarify how file paths are converted to custom element names:

#### Usage

Register all files in the `custom_elements` folder as custom elements using a prefix (e.g., `app`):
Register all files in the `custom_elements` folder as custom elements:

```js
eagerDefineCustomElementsFrom("custom_elements", { prefix: "app" });
```

| Filepath | Generated Custom Element Name |
|--------------------------------------------:|:------------------------------|
| `custom_elements/demo_element.js` | `<app-demo>` |
| `custom_elements/demo-element.js` | `<app-demo>` |
| `custom_elements/foo_bar_element.js` | `<app-foo-bar>` |
| `custom_elements/folder/foo_bar_element.js` | `<app-folder--foo-bar>` |

#### Conversion Rules

- Filenames are transformed into kebab-case (lowercase with hyphens).
- Words are separated by underscores (`_`) or hyphens (`-`) in the filename.
- The folder structure is reflected in the name using double hyphens (`--`) to separate folder names from the file name.
- A prefix (e.g., `app`) is added to the beginning of each custom element name.

#### Examples

| Filepath | Generated Custom Element Name |
|-------------------------------------|--------------------------------|
| `custom_elements/demo_element.js` | `<app-demo>` |
| `custom_elements/demo-element.js` | `<app-demo>` |
| `custom_elements/foo_bar_element.js`| `<app-foo-bar>` |
| `custom_elements/folder/foo_bar_element.js` | `<app-folder--foo-bar>` |
- A [configurable prefix](#documentation) is added to the beginning of each custom element name.

## Add a custom element with the built-in generator
## Generators

This gem adds a generator to generate new custom elements with:

```bash
```console
$ rails generate custom_element test
```

Expand All @@ -102,13 +114,13 @@ export default class extends HTMLElement {

which in turn will register a `<app-test></app-test>` custom element automatically in your app.

```bash
```console
$ rails generate custom_element test
```

To observe changes in your custom element's attributes, you need to set a static array of attribute names. The generator also supports setting those automatically:

```bash
```console
$ rails generate custom_element test attribute1
```

Expand Down Expand Up @@ -136,13 +148,15 @@ export default class extends HTMLElement {

`eagerDefineCustomElementsFrom(under, options)`

Currently supported `options`:
Currently supported optional `options`:

* `prefix`: The custom elements namespace/prefix.
* `prefix`: The custom elements namespace. (default: "app")

## Contributing

TODO
1. Fork the repository.
2. Create a feature branch.
3. Submit a pull request with a detailed description of changes.

## License

Expand Down
5 changes: 5 additions & 0 deletions app/assets/javascript/custom_elements-rails.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export function eagerDefineCustomElementsFrom(namespace, options = {}) {
const defaultOptions = {
prefix: 'app'
}

options = { ...defaultOptions, ...options }
const pathToElementName = (path) => {
const parts = path.split('/').map(p => p.replace(/_/g, '-'));
return `${options.prefix}-${parts.slice(0, -1).join('--')}${parts.length > 1 ? '--' : ''}${parts.at(-1)}`;
Expand Down
2 changes: 1 addition & 1 deletion test/dummy/app/javascript/custom_elements/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { eagerDefineCustomElementsFrom } from "custom_elements-rails"

eagerDefineCustomElementsFrom("custom_elements", { prefix: "app" })
eagerDefineCustomElementsFrom("custom_elements")
Loading