Current section
Files
Jump to
Current section
Files
src/glink.gleam
import glink/style.{type Style}
import glink/text
import glink/use_focus
import redraw.{type Component}
import redraw/dom/attribute.{type Attribute}
/// `box` is an essential Ink component to build your layout. It's like `<div style="display: flex">` in the browser.
@external(javascript, "./glink.ffi.mjs", "box")
pub fn box(
styles styles: List(Style),
attributes attrs: List(Attribute),
children children: List(Component),
) -> Component
/// [`box`](#box) without `attributes`.
pub fn box_(
styles styles: List(Style),
children children: List(Component),
) -> Component {
box(styles, [], children)
}
/// [`box`](#box) without `styles` and `attributes`.
pub fn box__(children: List(Component)) -> Component {
box([], [], children)
}
/// Adds one or more newline (\n) characters. Must be used within [`text`](#text) components.
@external(javascript, "./glink.ffi.mjs", "newline")
pub fn newline(count: Int) -> Component
/// [`newline`](#newline) with `count` set to `1`.
pub fn newline_() -> Component {
newline(1)
}
/// A flexible space that expands along the major axis of its containing layout.
/// It's useful as a shortcut for filling all the available spaces between elements.
@external(javascript, "./glink.ffi.mjs", "spacer")
pub fn spacer() -> Component
/// `static` component permanently renders its output above everything else.
/// It's useful for displaying activity like completed tasks or logs - things that
/// are not changing after they're rendered (hence the name "static").
///
/// It's preferred to use `static` for use cases like these, when you can't know
/// or control the amount of items that need to be rendered.
@external(javascript, "./glink.ffi.mjs", "static_")
pub fn static(
items: List(a),
styles: List(style.Style),
children: fn(a, Int) -> #(String, Component),
) -> Component
/// [`static`](#static) without `styles`.
pub fn static_(
items: List(a),
children: fn(a, Int) -> #(String, Component),
) -> Component {
static(items, [], children)
}
/// This component can display text, and change its style to make it colorful, bold, underline, italic or strikethrough.
@external(javascript, "./glink.ffi.mjs", "text")
pub fn text(props: List(text.Prop), children: List(Component)) -> Component
/// [`text`](#text) that use a single `String` for its `children`.
@external(javascript, "./glink.ffi.mjs", "text_")
pub fn text_(props: List(text.Prop), text: String) -> Component
/// [`text`](#text) without `props` and uses a single `String` for its `children`.
pub fn text__(text: String) -> Component {
text_([], text)
}
/// Function which transforms children output. It accepts children and must return transformed children too.
pub type Transform =
fn(String, Int) -> String
/// Transform a string representation of React components before they are written to output.
/// For example, you might want to apply a gradient to text, add a clickable link or create some text effects.
/// These use cases can't accept React nodes as input, they are expecting a string.
/// That's what `transform` component does, it gives you an output string of its child components and lets you transform it in any way.
@external(javascript, "./glink.ffi.mjs", "transform")
pub fn transform(transform: Transform, children: List(Component)) -> Component
pub type Size {
Size(
/// Element width.
width: Float,
/// Element height.
height: Float,
)
}
/// Measure the dimensions of a particular [`box`](#box) element.
@external(javascript, "./glink.ffi.mjs", "measure_element")
pub fn measure_element(node: node) -> Size
pub type Instance(error) {
Instance(
/// Replace previous root node with a new one or update props of the current root node.
rerender: fn(Component) -> Nil,
/// Manually unmount the whole Ink app.
unmount: fn(error) -> Nil,
/// Awaits a promise, which resolves when app is unmounted.
wait_until_exit: fn(fn() -> Nil) -> Nil,
cleanup: fn() -> Nil,
/// Clear output.
clear: fn() -> Nil,
)
}
/// Mount a component and render the output.
@external(javascript, "./glink.ffi.mjs", "render")
pub fn render(component: Component) -> Instance(error)
pub type App(error) {
App(
/// Exit (unmount) the whole Ink app.
exit: fn(error) -> Nil,
)
}
/// `use_app` is a React hook, which exposes a method to manually exit the app (unmount).
@external(javascript, "./glink.ffi.mjs", "use_app")
pub fn use_app() -> App(error)
pub type Focus {
Focus(
/// Determines whether this component is focused or not.
is_focused: Bool,
/// Allows focusing a specific element with the provided ID.
focus: fn(String) -> Nil,
)
}
/// Component that uses `use_focus` hook becomes "focusable" to Ink,
/// so when user presses `Tab`, Ink will switch focus to this component.
/// If there are multiple components that execute `use_focus` hook, focus will be
/// given to them in the order that these components are rendered in.
/// This hook returns an object with `is_focused` boolean property, which
/// determines if this component is focused or not.
@external(javascript, "./glink.ffi.mjs", "use_focus")
pub fn use_focus(props: List(use_focus.Prop)) -> Focus
/// [`use_focus`](#use_focus) without `props`.
pub fn use_focus_() -> Focus {
use_focus([])
}
pub type FocusManager {
FocusManager(
/// Enable focus management for all components.
enable_focus: fn() -> Nil,
/// Disable focus management for all components. Currently active component (if there's one) will lose its focus.
disable_focus: fn() -> Nil,
/// Switch focus to the next focusable component.
/// If there's no active component right now, focus will be given to the first focusable component.
/// If active component is the last in the list of focusable components, focus will be switched to the first component.
focus_next: fn() -> Nil,
/// Switch focus to the previous focusable component.
/// If there's no active component right now, focus will be given to the first focusable component.
/// If active component is the first in the list of focusable components, focus will be switched to the last component.
focus_previous: fn() -> Nil,
/// Switch focus to the element with provided ID.
/// If there's no element with that ID, focus will be given to the first focusable component.
focus: fn(String) -> Nil,
)
}
/// This hook exposes methods to enable or disable focus management for all
/// components or manually switch focus to next or previous components.
@external(javascript, "./glink.ffi.mjs", "use_focus_manager")
pub fn use_focus_manager() -> FocusManager
pub type InputHandler =
fn(String, Key) -> Nil
pub type Key {
/// Handy information about a key that was pressed.
Key(
/// Up arrow key was pressed.
up_arrow: Bool,
/// Down arrow key was pressed.
down_arrow: Bool,
/// Left arrow key was pressed.
left_arrow: Bool,
/// Right arrow key was pressed.
right_arrow: Bool,
/// Page Down key was pressed.
page_down: Bool,
/// Page Up key was pressed.
page_up: Bool,
/// Return (Enter) key was pressed.
return: Bool,
/// Escape key was pressed.
escape: Bool,
/// Ctrl key was pressed.
ctrl: Bool,
/// Shift key was pressed.
shift: Bool,
/// Tab key was pressed.
tab: Bool,
/// Backspace key was pressed.
backspace: Bool,
/// Delete key was pressed.
delete: Bool,
/// [Meta key](https://en.wikipedia.org/wiki/Meta_key) was pressed.
meta: Bool,
)
}
/// This hook is used for handling user input.
/// It's a more convenient alternative to using `StdinContext` and listening to `data` events.
/// The callback you pass to `use_input` is called for each character when user enters any input.
/// However, if user pastes text and it's more than one character, the callback will be called only once and the whole string will be passed as `input`.
@external(javascript, "./glink.ffi.mjs", "use_input")
pub fn use_input(handler: InputHandler, is_active: Bool) -> Nil
/// [use_input](#use_input) with `is_active` set to `True`.
pub fn use_input_(handler: InputHandler) -> Nil {
use_input(handler, True)
}
pub type ReadStream
pub type EventEmitter
pub type Stdin {
Stdin(
/// Stdin stream passed to `render()` in `options.stdin` or `process.stdin` by default. Useful if your app needs to handle user input.
/// **NOTE: Not yet useable.**
stdin: ReadStream,
/// Ink exposes this function via own `<StdinContext>` to be able to handle Ctrl+C, that's why you should use Ink's `set_raw_mode`.
/// If the `stdin` stream passed to Ink does not support `set_raw_mode`, this function does nothing.
set_raw_mode: fn(Bool) -> Nil,
/// A boolean flag determining if the current `stdin` supports `set_raw_mode`. A component using `set_raw_mode` might want to use `is_raw_mode_supported` to nicely fall back in environments where raw mode is not supported.
is_raw_mode_supported: Bool,
internal_exit_on_ctrl_c: Bool,
internal_event_emitter: EventEmitter,
)
}
/// `use_stdin` is a React hook, which exposes stdin stream.
@external(javascript, "./glink.ffi.mjs", "use_stdin")
pub fn use_stdin() -> Stdin
pub type WriteStream
pub type Stderr {
Stderr(
/// Stderr stream passed to `render()` in `options.stderr` or `process.stderr` by default.
/// **NOTE: Not yet useable.**
stderr: WriteStream,
/// Write any string to stderr, while preserving Ink's output.
/// It's useful when you want to display some external information outside of Ink's rendering and ensure there's no conflict between the two.
/// It's similar to `<Static>`, except it can't accept components, it only works with strings.
write: fn(String) -> Nil,
)
}
/// `use_stderr` is a React hook, which exposes stderr stream.
@external(javascript, "./glink.ffi.mjs", "use_stderr")
pub fn use_stderr() -> Stderr
pub type Stdout {
Stdout(
/// Stdout stream passed to `render()` in `options.stdout` or `process.stdout` by default.
/// **NOTE: Not yet useable.**
stdout: WriteStream,
/// Write any string to stdout, while preserving Ink's output.
/// It's useful when you want to display some external information outside of Ink's rendering and ensure there's no conflict between the two.
/// It's similar to `<Static>`, except it can't accept components, it only works with strings.
write: fn(String) -> Nil,
)
}
/// `use_stdout` is a React hook, which exposes stdout stream.
@external(javascript, "./glink.ffi.mjs", "use_stdout")
pub fn use_stdout() -> Stdout