Skip to content

Docs: add Available since component #235

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

Closed
wants to merge 1 commit into from
Closed
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
60 changes: 60 additions & 0 deletions docs/.vitepress/availableSinceMarkdownPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import MarkdownIt from 'markdown-it'

export interface AvailableSinceParams {
rails?: string
core?: string
description?: string
}

function parseAvailableSinceParams(info: string): AvailableSinceParams {
const basicMatch = info.trim().match(/^available_since(?:\s+(.*))?$/)
if (!basicMatch) return {}

const allParams = basicMatch[1] || ''
const params: AvailableSinceParams = {}

// Parse out key=value pairs first
const keyValueMatches = [...allParams.matchAll(/([a-z]+)(?:=("[^"]*"|[^\s"]+))?/g)]
for (const [, key, value] of keyValueMatches) {
let cleanValue = value ? value.replace(/^"|"$/g, '') : true

if (key === 'rails') params.rails = cleanValue as string
if (key === 'core') params.core = cleanValue as string
if (key === 'description') params.description = cleanValue as string
}

return params
}

export function availableSinceMarkdownPlugin(md: MarkdownIt) {
md.block.ruler.before('paragraph', 'available_since_oneliner', (state, start, end, silent) => {
const line = state.getLines(start, start + 1, 0, false).trim()

const match = line.match(/^@available_since\s+(.+)$/)
if (!match) return false

if (silent) return true

const params = parseAvailableSinceParams(`available_since ${match[1]}`)
const token = state.push('available_since_oneliner', '', 0)

token.content = renderAvailableSince(params, md)
token.map = [start, start + 1]

state.line = start + 1
return true
})

// Render the one-liner available_since token
md.renderer.rules.available_since_oneliner = (tokens, idx) => {
return tokens[idx].content + '\n'
}
}

function renderAvailableSince(params: AvailableSinceParams, md: MarkdownIt): string {
const railsAttr = params.rails ? `rails="${md.utils.escapeHtml(params.rails)}"` : ''
const coreAttr = params.core ? `core="${md.utils.escapeHtml(params.core)}"` : ''
const descriptionAttr = params.description ? `description="${md.utils.escapeHtml(params.description)}"` : ''

return `<AvailableSince ${railsAttr} ${coreAttr} ${descriptionAttr} />`
}
2 changes: 2 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineConfig } from 'vitepress'
import { availableSinceMarkdownPlugin } from './availableSinceMarkdownPlugin'
import { tabsMarkdownPlugin } from './vitepress-plugin-tabs/tabsMarkdownPlugin'

const title = 'Inertia Rails'
Expand All @@ -16,6 +17,7 @@ export default defineConfig({
markdown: {
config(md) {
md.use(tabsMarkdownPlugin)
md.use(availableSinceMarkdownPlugin)
},
},

Expand Down
257 changes: 257 additions & 0 deletions docs/.vitepress/theme/components/AvailableSince.vue

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions docs/.vitepress/theme/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import AvailableSince from './AvailableSince.vue'

export {
AvailableSince,
}
2 changes: 2 additions & 0 deletions docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Theme } from 'vitepress'
import { enhanceAppWithTabs } from 'vitepress-plugin-tabs/client'
import DefaultTheme from 'vitepress/theme'
import { h } from 'vue'
import { AvailableSince } from './components'
import { setupFrameworksTabs } from './frameworksTabs'
import './style.css'

Expand All @@ -15,6 +16,7 @@ export default {
},
enhanceApp({ app, router, siteData }) {
enhanceAppWithTabs(app)
app.component('AvailableSince', AvailableSince)
},
setup() {
setupFrameworksTabs()
Expand Down
9 changes: 8 additions & 1 deletion docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ Use `component_path_resolver` to customize component path resolution when [`defa

### `deep_merge_shared_data`

@available_since rails=3.8.0

When enabled, props will be deep merged with shared data, combining hashes
with the same keys instead of replacing them.

**Default**: `false`


### `default_render`

Overrides Rails default rendering behavior to render using Inertia by default.
Expand All @@ -53,6 +56,8 @@ Overrides Rails default rendering behavior to render using Inertia by default.

### `encrypt_history`

@available_since rails=3.7.0 core=2.0.0

When enabled, you instruct Inertia to encrypt your app's history, it uses
the browser's built-in [`crypto` api](https://developer.mozilla.org/en-US/docs/Web/API/Crypto)
to encrypt the current page's data before pushing it to the history state.
Expand All @@ -61,11 +66,13 @@ to encrypt the current page's data before pushing it to the history state.

### `ssr_enabled` _(experimental)_

@available_since rails=3.6.0 core=2.0.0

Whether to use a JavaScript server to pre-render your JavaScript pages,
allowing your visitors to receive fully rendered HTML when they first visit
your application.

Requires a JS server to be available at `ssr_url`. [_Example_](https://github.com/ElMassimo/inertia-rails-ssr-template)
Requires a JavaScript server to be available at `ssr_url`. [_Example_](https://github.com/ElMassimo/inertia-rails-ssr-template)

**Default**: `false`

Expand Down
2 changes: 2 additions & 0 deletions docs/guide/deferred-props.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Deferred props

@available_since rails=3.6.0 core=2.0.0

Inertia's deferred props feature allows you to defer the loading of certain page data until after the initial page render. This can be useful for improving the perceived performance of your app by allowing the initial page render to happen as quickly as possible.

## Server side
Expand Down
37 changes: 30 additions & 7 deletions docs/guide/merging-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,52 @@ By default, Inertia overwrites props with the same name when reloading a page. H

## Server side

> `deep_merge` requires `@inertiajs/core` v2.0.8 or higher, and `inertia_rails` v3.8.0 or higher.
### Using `merge`

To specify that a prop should be merged, use the `merge` or `deep_merge` method on the prop's value.
@available_since rails=3.8.0 core=2.0.8

Use `merge` for merging simple arrays, and `deep_merge` for handling nested objects that include arrays or complex structures, such as pagination objects.
To specify that a prop should be merged, use the `merge` method on the prop's value. This is ideal for merging simple arrays.

On the client side, Inertia detects that this prop should be merged. If the prop returns an array, it will append the response to the current prop value. If it's an object, it will merge the response with the current prop value.

```ruby
class UsersController < ApplicationController
include Pagy::Backend

def index
pagy, records = pagy(User.all)
_pagy, records = pagy(User.all)

render inertia: {
# simple array:
users: InertiaRails.merge { records.as_json(...) },
# with match_on parameter for smart merging:
products: InertiaRails.merge(match_on: 'id') { Product.all.as_json(...) },
}
end
end
```

### Using `deep_merge`

@available_since rails=3.8.0 core=2.0.8

For handling nested objects that include arrays or complex structures, such as pagination objects, use the `deep_merge` method.

```ruby
class UsersController < ApplicationController
include Pagy::Backend

def index
pagy, records = pagy(User.all)

render inertia: {
# pagination object:
data: InertiaRails.deep_merge {
{
records: records.as_json(...),
pagy: pagy_metadata(pagy)
}
},
# with match_on parameter for smart merging:
products: InertiaRails.merge(match_on: 'id') { Product.all.as_json(...) },
# nested objects with match_on:
categories: InertiaRails.deep_merge(match_on: %w[items.id tags.id]) {
{
Expand All @@ -41,10 +62,12 @@ class UsersController < ApplicationController
end
```

On the client side, Inertia detects that this prop should be merged. If the prop returns an array, it will append the response to the current prop value. If it's an object, it will merge the response with the current prop value. If you have opted to `deepMerge`, Inertia ensures a deep merge of the entire structure.
If you have opted to use `deep_merge`, Inertia ensures a deep merge of the entire structure, including nested objects and arrays.

### Smart merging with `match_on`

@available_since rails=master core=2.0.13

By default, arrays are simply appended during merging. If you need to update specific items in an array or replace them based on a unique identifier, you can use the `match_on` parameter.

The `match_on` parameter enables smart merging by specifying a field to match on when merging arrays of objects:
Expand Down