//// 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