Module: Tuile::Component::HasValue

Includes:
HasValidation
Included in:
AbstractStringField, AbstractWrappingField, Checkbox, CheckboxGroup, ComboBox, DateTimeField, RadioGroup, Select
Defined in:
lib/tuile/component/has_value.rb,
sig/tuile.rbs

Overview

The value seam every input component shares: a settable/gettable #value of any type, an #on_value_change listener, #empty?, and #clear. A form (a future binder) drives a mix of field types uniformly through it, not caring that a TextField's value is a String while another field's is a domain object.

field.on_value_change = ->(v) { puts "now: #{v.inspect}" }
field.value = "hello"   # fires the listener
field.clear             # value = empty_value, fires again

The default #value=/#value keep the value in @value and are enough for a component with nothing more natural — you get a repaint and the listener for free. An includer whose value lives elsewhere overrides both (AbstractStringField backs them with its text buffer). Override #empty_value when the empty sentinel isn't nil (a text field's is "").

HasValidation comes with it, so every field carries the error_message a validator writes and paints its own error ink.

Implementation details

Deliberately smaller than Vaadin's HasValue: read-only, required-indicator, the from-client/old-value event payload, and converters all belong to the not-yet-built form layer, not here.

Instance Attribute Summary collapse

Attributes included from HasValidation

#on_error_message_change

Instance Method Summary collapse

Instance Attribute Details

#on_value_changeProc, ...

@return — one-arg callable fired with the new value whenever #value actually changes — never on a no-op set.

Returns:

  • (Proc, Method, nil)


33
34
35
# File 'lib/tuile/component/has_value.rb', line 33

def on_value_change
  @on_value_change
end

Instance Method Details

#clearvoid

This method returns an undefined value.

Resets #value to #empty_value.

An includer whose input can outrun its value (Tuile::Component::HasBadInput) must clear the input: a field holding bad input already reads empty_value, so inheriting this default — over a #value= that returns early on a no-op set — is a clear that leaves the garbage on screen.



62
# File 'lib/tuile/component/has_value.rb', line 62

def clear = (self.value = empty_value)

#empty?Boolean

Empty of value: a field whose parse is partial reports true while the user is looking at glyphs it could not use, so ask Tuile::Component::HasBadInput#bad_input? first.

@return — true iff #value equals #empty_value.

Returns:

  • (Boolean)


53
# File 'lib/tuile/component/has_value.rb', line 53

def empty? = value == empty_value

#empty_valueObject

@return — the value #empty?/#clear treat as empty; nil unless an includer overrides it.

Returns:

  • (Object)


66
# File 'lib/tuile/component/has_value.rb', line 66

def empty_value = nil

#error_bg_colorColor?

The invalid well, picked up by everything this component paints — including the inner face of a composed field and the List of a group, neither of which forwards anything: both declare no background of their own, so the ordinary chain walks up to this (overrides Tuile::Component#error_bg_color).

Returns:



6733
# File 'sig/tuile.rbs', line 6733

def error_bg_color: () -> Color?

#error_ink?Boolean

Whether to paint the invalid well right now. Its own hook because Tuile::Component::HasBadInput widens it: a field holding input its value cannot represent is invalid on the face too, even with no verdict written.

Returns:

  • (Boolean)


6738
# File 'sig/tuile.rbs', line 6738

def error_ink?: () -> bool

#error_messageStyledString?

@return — why the field is invalid, or nil when it is not; nil until something sets it.

Returns:



6716
# File 'sig/tuile.rbs', line 6716

def error_message: () -> StyledString?

#error_message=void

This method returns an undefined value.

Sets the verdict and repaints the field in Theme#error_color; nil clears it. No-op (no repaint, no listener) when unchanged. A String is parsed via StyledString.parse, as Tuile::Component::HasCaption#caption= does.

Safe on a detached field — an app validates a form it assembled but has not mounted, and Tuile::Component#invalidate is already a no-op there.

@param new_message

Parameters:



6726
# File 'sig/tuile.rbs', line 6726

def error_message=: ((String | StyledString)? new_message) -> void

#focusable?Boolean

Input fields are focusable by default (overrides Tuile::Component#focusable?); a read-only display field could override back to false. Only focusable? lives here — tab_stop? diverges between leaf fields and composing wrappers, so it stays per-class (design/decisions.md D_integer_field).

Returns:

  • (Boolean)


74
# File 'lib/tuile/component/has_value.rb', line 74

def focusable? = true

#inspect_details::Array[String]

Adds value=… to Tuile::Component#inspect, omitted while the value is nil.

Returns:

  • (::Array[String])


80
81
82
83
84
85
86
87
88
# File 'lib/tuile/component/has_value.rb', line 80

def inspect_details
  v = value
  return super if v.nil?

  # Truncate before #inspect, not after: a TextArea's value is its whole
  # buffer.
  v = "#{v[0, 40]}" if v.is_a?(String) && v.length > 40
  super + ["value=#{v.inspect}"]
end

#valueObject

@return — the current value; nil until first set.

Returns:

  • (Object)


36
# File 'lib/tuile/component/has_value.rb', line 36

def value = @value

#value=(new_value) ⇒ void

This method returns an undefined value.

No-op (no repaint, no listener) when equal to the current value.

@param new_value

Parameters:

  • new_value (Object)


41
42
43
44
45
46
47
# File 'lib/tuile/component/has_value.rb', line 41

def value=(new_value)
  return if value == new_value

  @value = new_value
  invalidate
  on_value_change&.call(new_value)
end