ソース情報
- リポジトリ
- dvcrn/skills
- ソースの最終更新活動
- 2026年8月26日 01:13
- 検出された SKILL.md の言語
- 英語
- スター
- 0
- フォーク
- 0
インストール方法
デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。
ソースファイルを確認
インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。
メニュー
デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。
インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/dvcrn/skills --skill phoenix-colocated-hooksコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
Install and configure PostHog in an Elixir/Phoenix project, including backend SDK, runtime configuration, an app-owned analytics boundary, identity wiring, JS client assets, template wiring, Plug middleware, and verification. Use when adding PostHog analytics or event capture to an Elixir or Phoenix application.
Install and configure Sentry in an Elixir or Phoenix project using official modern defaults, including runtime DSN configuration, Sentry.LoggerHandler with log message capture and rate limiting, Sentry.PlugContext placement, Cowboy/Bandit server detection, Oban error reporting, PII scrubbing, source code packaging for releases, and verification. Use when adding Sentry error monitoring or updating Sentry setup in an Elixir codebase.
SwiftUI state management using @Observable Store containers (Observation framework, iOS 17+), @Environment injection, store composition, derived state, and async mutation patterns. Use when designing or reviewing Store architecture, migrating from ObservableObject/Combine, translating React hooks or React Query patterns to SwiftUI, or implementing shared app-wide state containers.
SKILL.md を表示中
| name | phoenix-colocated-hooks |
| description | Use when we need an explanation of phoenix colocated hooks |
Colocated hooks let you define Phoenix LiveView client hooks directly alongside your HEEx templates. They live inside a <script> block with a special :type and are compiled into a JS manifest that bundlers can import.
.heex/~H templateDefine a hook inside your LiveView template using the Phoenix.LiveView.ColocatedHook type, and reference it with phx-hook on an element:
defmodule MyAppWeb.DemoLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, socket}
end
def render(assigns) do
~H"""
<input
type="text"
name="user[phone_number]"
id="user-phone-number"
phx-hook=".PhoneNumber"
/>
<script :type={Phoenix.LiveView.ColocatedHook} name=".PhoneNumber">
export default {
mounted() {
this.el.addEventListener("input", e => {
let match = this.el.value.replace(/\D/g, "").match(/^(\d{3})(\d{3})(\d{4})$/)
if (match) {
this.el.value = `${match[1]}-${match[2]}-${match[3]}`
}
})
}
}
</script>
"""
end
end
Key points:
<script> tag uses :type={Phoenix.LiveView.ColocatedHook}name attribute is required and must start with a dot (e.g. .PhoneNumber, not PhoneNumber)phx-hook attribute value must also include the dot (e.g. phx-hook=".PhoneNumber", not phx-hook="PhoneNumber")MyAppWeb.DemoLive.PhoneNumber)At compile time, Phoenix extracts colocated hooks and writes them into a generated JS folder (typically under _build). A manifest file aggregates hooks as named exports for your bundler:
import { hooks } from "phoenix-colocated/my_app"
console.log(hooks)
/*
{
"MyAppWeb.DemoLive.PhoneNumber": { ... },
...
}
*/
Important details:
mix compile before running your assets pipeline so hooks existcompile runs before assets.deploy:# Instead of
release: ["assets.deploy", "release"]
# Use
release: ["compile", "assets.deploy", "release"]
Runtime hooks are colocated hooks that are not extracted into the JS manifest. They are executed directly in the browser, which is useful when you cannot change the main JS bundle (for example, when extending Phoenix.LiveDashboard).
To register a runtime hook, add the runtime attribute and make the script body evaluate to the hook object (no export default):
<script :type={Phoenix.LiveView.ColocatedHook} name=".MyHook" runtime>
{
mounted() {
// your hook logic here
}
}
</script>
LiveView wraps this content into a function on window:
window["phx_hook_HASH"] = function () {
return {
mounted() {
// ...
}
}
}
Notes and caveats:
name convention and get module-prefixedIf you use runtime hooks in an app with Content Security Policy (CSP), inline scripts must be allowed, usually via a nonce.
Example with nonce:
<script
:type={Phoenix.LiveView.ColocatedHook}
name=".MyHook"
runtime
nonce={@script_csp_nonce}
>
function () {
return {
mounted() {
// logic
}
}
}
</script>
The nonce in @script_csp_nonce must match the one advertised in your Content-Security-Policy response header.
Use this skill when you need:
When not to use colocated hooks:
phoenix-hooks skill).phx-hook semantics (no LiveView hook lifecycle, just exports/utilities), use Phoenix.LiveView.ColocatedJS instead (see the phoenix-colocated-js skill).If Alpine.js is already installed in your project, use it for local UI state and use LiveView hooks for coordinating with the server. If Alpine.js is not installed and you need rich client-side state, ask the team whether you should add Alpine.js before implementing these patterns.
Use Alpine for local UI state and LiveView hooks for server coordination. Prefer Phoenix.LiveView.JS for simple UI transitions; reach for hooks only when you need server feedback to update client state.
<%!-- Define as a ColocatedHook; note dotted name --%>
<script :type={Phoenix.LiveView.ColocatedHook} name=".SaveHook">
export default {
mounted() {
this.handleEvent("save_complete", ({ success, error }) => {
const alpine = this.el._x_dataStack?.[0];
if (!alpine) return;
alpine.loading = false;
if (!success) alpine.error = error;
})
}
}
// Elements using this hook must have an id
// Use with: phx-hook=".SaveHook" (include the dot)
</script>
<div id="save-form" phx-hook=".SaveHook" x-data="{
loading: false,
error: '',
save() {
this.loading = true;
this.error = '';
this.$refs.saveButton.click();
}
}">
<input x-on:keydown.cmd.s.prevent="save()" />
<span x-show="error" x-text="error"></span>
<button x-on:click="save()" x-bind:disabled="loading">
<span x-show="!loading">Save</span>
<span x-show="loading">Saving...</span>
</button>
<button x-ref="saveButton" phx-click="save" class="hidden"></button>
</div>
Server handler example:
def handle_event("save", params, socket) do
case save_operation(params) do
{:ok, _} ->
{:noreply, push_navigate(socket, to: "/success")}
{:error, reason} ->
socket = push_event(socket, "save_complete", %{success: false, error: reason})
{:noreply, socket}
end
end
.MyHook).phx-hook too; names must match exactly.id.this.el._x_dataStack?.[0].x-show, ensure the hidden state sets style="display: none;" initially to avoid FOUC.x-on:event syntax, not @event.Jason.encode!.Prefer Phoenix.LiveView.JS for fast, declarative UI changes.
<%=
JS.show(to: "#dialog-id", display: "flex")
|> JS.add_class("backdrop-fade-in", to: "#dialog-id-backdrop")
|> JS.add_class("modal-spring-in", to: "#dialog-id-content")
%>
<%=
JS.add_class("backdrop-fade-out", to: "#dialog-id-backdrop")
|> JS.add_class("modal-spring-out", to: "#dialog-id-content")
|> JS.hide(to: "#dialog-id", time: 200)
|> JS.remove_class("backdrop-fade-in backdrop-fade-out", to: "#dialog-id-backdrop")
|> JS.remove_class("modal-spring-in modal-spring-out", to: "#dialog-id-content")
%>
Implementation notes:
style="display: none;").phx-click-loading:opacity-50 utility.JS.push/2.