defmodule Corex.Clipboard do @moduledoc ~S''' Phoenix implementation of [Zag.js Clipboard](https://zagjs.com/components/react/clipboard). ## Examples ### Basic Usage This example assumes the import of `.icon` from `Core Components` ```heex <.clipboard id="my-clipboard" value="Text to copy"> <:label>Copy to clipboard <:trigger> <.icon name="hero-clipboard" class="icon data-copy" /> <.icon name="hero-check" class="icon data-copied" /> ``` ### With Callback This example assumes the import of `.icon` from `Core Components` ```heex <.clipboard id="my-clipboard" value="Text to copy" on_copy="clipboard_copied"> <:label>Copy to clipboard <:trigger> <.icon name="hero-clipboard" class="icon data-copy" /> <.icon name="hero-check" class="icon data-copied" /> ``` ```elixir def handle_event("clipboard_copied", %{"value" => value}, socket) do {:noreply, put_flash(socket, :info, "Copied: #{value}")} end ``` ## API Control In order to use the API, you must use an id on the component ***Client-side*** ```heex ``` ***Server-side*** ```elixir def handle_event("copy_text", _, socket) do {:noreply, Corex.Clipboard.copy(socket, "my-clipboard", "Text to copy")} end ``` ## Styling Use data attributes to target elements: ```css [data-scope="clipboard"][data-part="root"] {} [data-scope="clipboard"][data-part="trigger"] {} [data-scope="clipboard"][data-part="control"] {} [data-scope="clipboard"][data-part="input"] {} ``` If you wish to use the default Corex styling, you can use the class `clipboard` on the component. This requires to install mix corex.design first and import the component css file. ```css @import "../corex/main.css"; @import "../corex/tokens/themes/neo/light.css"; @import "../corex/components/clipboard.css"; ``` You can then use modifiers ```heex <.clipboard class="clipboard clipboard--accent clipboard--lg"> ``` Learn more about modifiers and [Corex Design](https://corex-ui.com/components/clipboard#modifiers) ''' @doc type: :component use Phoenix.Component alias Corex.Clipboard.Anatomy.{Props, Root, Label, Control, Input, Trigger} alias Corex.Clipboard.Connect @doc """ Renders a clipboard component. """ attr(:id, :string, required: false, doc: "The id of the clipboard, useful for API to identify the clipboard" ) attr(:value, :string, default: nil, doc: "The initial value or the controlled value to copy to clipboard" ) attr(:controlled, :boolean, default: false, doc: "Whether the clipboard is controlled. Only in LiveView, the on_value_change event is required" ) attr(:timeout, :integer, default: nil, doc: "The timeout in milliseconds before resetting the copied state" ) attr(:dir, :string, default: nil, values: [nil, "ltr", "rtl"], doc: "The direction of the clipboard. When nil, derived from document (html lang + config :rtl_locales)" ) attr(:on_copy, :string, default: nil, doc: "The server event name when the value is copied" ) attr(:on_copy_client, :string, default: nil, doc: "The client event name when the value is copied" ) attr(:on_value_change, :string, default: nil, doc: "The server event name when the value changes (for controlled mode)" ) attr(:trigger_aria_label, :string, default: nil, doc: "Accessible name for the trigger button when it contains only an icon (e.g. \"Copy to clipboard\")" ) attr(:input_aria_label, :string, default: nil, doc: "Accessible name for the input when it's not associated with a visible label (e.g. \"Value to copy\")" ) attr(:rest, :global) slot :label, required: false do attr(:class, :string, required: false) end slot :trigger, required: false do attr(:class, :string, required: false) end def clipboard(assigns) do assigns = assigns |> assign_new(:id, fn -> "clipboard-#{System.unique_integer([:positive])}" end) ~H"""