//// Implementation for HTML and SVG attributes usable in React and in browser.
//// Contrarily to Lustre, every attributes can take arbitrary data, because
//// they're directly bind in the underlying component's props.
////
//// All available attributes can be found in the
//// [React.dev](https://react.dev/reference/react-dom/components/common#common)
//// documentation for detailed information, as well as on
//// [MDN](https://developer.mozilla.org/docs/Web/API/Element).
import gleam/dynamic.{type Dynamic}
import gleam/fetch/form_data.{type FormData}
import gleam/option
import gleam/string
import redraw/internal/unsafe
import redraw/ref
/// Attribute linked on an HTML or SVG node. Think about like a `prop` in React.
pub opaque type Attribute {
Attribute(key: String, content: Dynamic)
}
/// Generic attribute. `key` will be the key in the HTML attributes as-is,
/// while content can be anything. `content` will be converted by React to
/// strings, so be careful to not send complicated data structure, but booleans,
/// strings numbers, etc. are plainly supported.
///
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Reference/Attributes)
pub fn attribute(key: String, content: a) -> Attribute {
let content = unsafe.coerce(content)
Attribute(key:, content:)
}
/// [Documentation](https://developer.mozilla.org/docs/Web/API/HTMLAnchorElement/href)
pub fn href(url: String) -> Attribute {
attribute("href", url)
}
/// [Documentation](https://developer.mozilla.org/docs/Web/API/HTMLAnchorElement/target)
pub fn target(value: String) -> Attribute {
attribute("target", value)
}
/// [Documentation](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement/src)
pub fn src(value: String) -> Attribute {
attribute("src", value)
}
/// To follow Lustre pattern, `class` is additive. When using multiple `class`
/// on a single element, they will all be applied on that element.
///
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/class)
pub fn class(value: String) -> Attribute {
attribute("className", value)
}
/// [Documentation](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement/alt)
pub fn alt(value: String) -> Attribute {
attribute("alt", value)
}
/// Inner HTML data are HTML that will not be verified sanitized.
/// Be careful when using it. You should almost always prefer to use
/// `redraw/element/html`.
pub type InnerHTML
/// The `inner_html` data should be created as close to where the HTML is
/// generated as possible. This ensures that all raw HTML being used in your
/// code is explicitly marked as such, and that only variables that you expect
/// to contain HTML are passed to `dangerously_set_inner_html`. It is not
/// recommended to create the object inline like
/// `html.div([attribute.dangerously_set_inner_html(attribute.inner_html(markup))], [])` \
/// [Documentation](https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html)
@external(javascript, "./attribute.ffi.mjs", "innerHTML")
pub fn inner_html(html: String) -> InnerHTML
/// Overrides the innerHTML property of the DOM node and displays the passed
/// HTML inside. This should be used with extreme caution! If the HTML inside
/// isn’t trusted (for example, if it’s based on user data), you risk
/// introducing an XSS vulnerability. \
/// [Documentation](https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html)
pub fn dangerously_set_inner_html(inner_html: InnerHTML) -> Attribute {
attribute("dangerouslySetInnerHTML", inner_html)
}
/// A ref object from `redraw.use_ref`. Your ref will be filled with the DOM
/// element for this node. Contrarily to JS React, when using a Ref, you're
/// forced to use an optional type here. Because when using this function, you
/// want to get a reference from a real DOM node, meaning at the initialization
/// of the reference, you won't have any data. Use `ref_` when you want full
/// control over the ref you send to the Component. \
/// [Documentation](https://react.dev/reference/react-dom/components/common#manipulating-a-dom-node-with-a-ref)
pub fn ref(ref: ref.Ref(option.Option(a))) -> Attribute {
use dom_ref <- attribute("ref")
ref.assign(ref, option.Some(dom_ref))
}
/// A ref callback function. The callback will be provided with the DOM element
/// for this node. Use this function to get control on the ref provided by the
/// DOM node or the component. \
/// [Documentation](https://react.dev/reference/react-dom/components/common#manipulating-a-dom-node-with-a-ref)
pub fn ref_(ref: fn(a) -> Nil) -> Attribute {
attribute("ref", ref)
}
/// If `True`, suppresses the warning that React shows for elements that both
/// have `children` and `content_editable(True)` (which normally do not work
/// together). Use this if you’re building a text input library that manages
/// the `contentEditable` content manually.
pub fn suppress_content_editable_warning(value: Bool) -> Attribute {
attribute("suppressContentEditableWarning", value)
}
/// If you use [server rendering](https://react.dev/reference/react-dom/server),
/// normally there is a warning when the server and the client render different
/// content. In some rare cases (like timestamps), it is very hard or impossible
/// to guarantee an exact match. If you set suppressHydrationWarning to true,
/// React will not warn you about mismatches in the attributes and the content
/// of that element. It only works one level deep, and is intended to be used
/// as an escape hatch. Don’t overuse it.
/// [Read about suppressing hydration errors.](https://react.dev/reference/react-dom/client/hydrateRoot#suppressing-unavoidable-hydration-mismatch-errors)
pub fn suppress_hydration_warning(value: Bool) -> Attribute {
attribute("suppressHydrationWarning", value)
}
@external(javascript, "./attribute.ffi.mjs", "convertStyle")
fn convert_style(styles: List(#(String, String))) -> a
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/style)
pub fn style(styles: List(#(String, String))) -> Attribute {
attribute("style", convert_style(styles))
}
/// Set aria attribute on the node. Should be used like `aria("valuenow", "75")`.
pub fn aria(key: String, value: String) -> Attribute {
attribute("aria-" <> key, value)
}
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/accesskey)
pub fn access_key(value: String) -> Attribute {
attribute("accessKey", value)
}
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/autocapitalize)
pub fn auto_capitalize(value: String) -> Attribute {
attribute("autoCapitalize", value)
}
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/autofocus)
pub fn auto_focus(value: Bool) -> Attribute {
attribute("autoFocus", value)
}
/// Alias of `class`. \
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/class)
pub fn class_name(value: String) -> Attribute {
attribute("className", value)
}
/// Specifies the value of a metadata name defined by the `` `name`
/// attribute. It takes a string as its value, and the expected syntax varies
/// depending on the `name` value used. \
/// [Documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/content)
pub fn content(value: String) -> Attribute {
attribute("content", value)
}
/// If true, the browser lets the user edit the rendered element directly.
/// This is used to implement rich text input libraries like Lexical. React
/// warns if you try to pass React children to an element with
/// `content_editable(True)` because React will not be able to update its content
/// after user edits. \
/// [Documentation](https://developer.mozilla.org/docs/Web/API/HTML/Global_attributes/contenteditable)
pub fn content_editable(value: Bool) -> Attribute {
attribute("contentEditable", value)
}
/// [Documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/crossorigin)
pub fn cross_origin(value: String) -> Attribute {
attribute("crossOrigin", value)
}
/// Data attributes let you attach some string data to the element, for example
/// `data("fruit", "banana")`. In React, they are not commonly used because you
/// would usually read data from props or state instead. \
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/data-*)
pub fn data(key: String, value: String) -> Attribute {
attribute("data-" <> key, value)
}
/// Directionality of an element text.
pub type Dir {
Ltr
Rtl
}
/// Specifies the text direction of the element. \
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/dir)
pub fn dir(value: Dir) -> Attribute {
let value = case value {
Ltr -> "ltr"
Rtl -> "rtl"
}
attribute("dir", value)
}
/// [Documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/dirname)
pub fn dirname(value: String) -> Attribute {
attribute("dirName", value)
}
/// Specifies whether the element is draggable. Part of HTML Drag and Drop API. \
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/draggable)
pub fn draggable(value: Bool) -> Attribute {
attribute("draggable", value)
}
/// Specifies which action to present for the enter key on virtual keyboards. \
/// [Documentation](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/enterkeyhint)
pub fn enter_key_hint(value: String) -> Attribute {
attribute("enterKeyHint", value)
}
/// [Documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/exportparts)
pub fn export_parts(value: List(String)) -> Attribute {
attribute("exportParts", string.join(value, with: ", "))
}
/// [Documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/elementtiming)
pub fn element_timing(value: String) -> Attribute {
attribute("elementTiming", value)
}
/// For