line-message-builder 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.document +3 -0
- data/.release-please-manifest.json +1 -1
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +35 -0
- data/CONVENTIONS.md +36 -0
- data/README.md +49 -31
- data/lib/line/message/builder/actions/message.rb +67 -1
- data/lib/line/message/builder/actions/postback.rb +71 -1
- data/lib/line/message/builder/actions.rb +18 -1
- data/lib/line/message/builder/base.rb +113 -3
- data/lib/line/message/builder/container.rb +125 -5
- data/lib/line/message/builder/context.rb +111 -3
- data/lib/line/message/builder/flex/actionable.rb +46 -1
- data/lib/line/message/builder/flex/box.rb +191 -15
- data/lib/line/message/builder/flex/bubble.rb +96 -8
- data/lib/line/message/builder/flex/builder.rb +74 -8
- data/lib/line/message/builder/flex/button.rb +104 -17
- data/lib/line/message/builder/flex/carousel.rb +71 -8
- data/lib/line/message/builder/flex/image.rb +105 -20
- data/lib/line/message/builder/flex/partial.rb +94 -9
- data/lib/line/message/builder/flex/position.rb +122 -12
- data/lib/line/message/builder/flex/separator.rb +41 -0
- data/lib/line/message/builder/flex/size.rb +65 -7
- data/lib/line/message/builder/flex/span.rb +110 -0
- data/lib/line/message/builder/flex/text.rb +176 -28
- data/lib/line/message/builder/flex.rb +56 -12
- data/lib/line/message/builder/quick_reply.rb +16 -4
- data/lib/line/message/builder/text.rb +12 -1
- data/lib/line/message/builder/version.rb +1 -1
- data/lib/line/message/builder.rb +33 -3
- data/lib/line/message/rspec/matchers/have_flex_component.rb +11 -0
- data/lib/line/message/rspec/matchers/have_flex_separator.rb +20 -0
- data/lib/line/message/rspec/matchers.rb +1 -0
- data/lib/line/message/rspec.rb +14 -0
- data/llm.txt +437 -0
- metadata +6 -1
@@ -3,31 +3,151 @@
|
|
3
3
|
module Line
|
4
4
|
module Message
|
5
5
|
module Builder
|
6
|
-
# The
|
7
|
-
|
6
|
+
# The `Container` class is the top-level entry point for constructing a batch
|
7
|
+
# of LINE messages using the builder DSL. It acts as a holder for one or
|
8
|
+
# more individual message objects (such as {Text} or {Flex} messages).
|
9
|
+
#
|
10
|
+
# When you use `Line::Message::Builder.with {}`, you are operating within
|
11
|
+
# the context of a `Container` instance. This container allows you to define
|
12
|
+
# multiple messages that can be sent together in a single API call to LINE,
|
13
|
+
# although the LINE API typically expects an array of message objects,
|
14
|
+
# which this container helps to build.
|
15
|
+
#
|
16
|
+
# Each message added to the container can also have its own quick reply.
|
17
|
+
#
|
18
|
+
# @example Building multiple messages
|
19
|
+
# message_payload = Line::Message::Builder.with do
|
20
|
+
# text "Hello, this is the first message!"
|
21
|
+
# flex alt_text: "This is a Flex Message" do
|
22
|
+
# bubble do
|
23
|
+
# body do
|
24
|
+
# body.text "This is a Flex Message body."
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
# end.build # => Returns an array of message hashes
|
29
|
+
#
|
30
|
+
# @see Base
|
31
|
+
# @see Text
|
32
|
+
# @see Flex::Builder
|
33
|
+
# @see QuickReply
|
34
|
+
class Container
|
35
|
+
# @!attribute [r] context
|
36
|
+
# @return [Context] The context object, which can hold external data or
|
37
|
+
# helper methods accessible within the builder blocks.
|
8
38
|
attr_reader :context
|
9
39
|
|
10
|
-
|
11
|
-
|
40
|
+
# Initializes a new message container.
|
41
|
+
# This is typically not called directly but through `Line::Message::Builder.with`.
|
42
|
+
# The provided block is instance-eval'd, allowing DSL methods like
|
43
|
+
# {#text} and {#flex} to be called directly on the container instance.
|
44
|
+
#
|
45
|
+
# @param context [Object, nil] An optional context object that can be used
|
46
|
+
# to share data or helper methods within the builder block. It's wrapped
|
47
|
+
# in a {Context} object.
|
48
|
+
# @param mode [Symbol] The mode to use for building messages. Can be either
|
49
|
+
# `:api` (default) for direct LINE Messaging API format or `:sdkv2` for
|
50
|
+
# LINE Bot SDK v2 compatible format.
|
51
|
+
# @param block [Proc] A block containing DSL calls to define messages
|
52
|
+
# (e.g., `text "Hello"`, `flex { ... }`).
|
53
|
+
def initialize(context: nil, mode: :api, &block)
|
54
|
+
@messages = [] # Initializes an empty array to store message objects
|
55
|
+
@context = Context.new(context, mode:)
|
12
56
|
|
13
|
-
|
57
|
+
instance_eval(&block) if ::Kernel.block_given?
|
14
58
|
end
|
15
59
|
|
60
|
+
# Creates a new {Text} message and adds it to this container.
|
61
|
+
#
|
62
|
+
# @param text [String] The text content of the message.
|
63
|
+
# @param options [Hash] Additional options for the text message,
|
64
|
+
# such as `:quick_reply`. See {Text#initialize}.
|
65
|
+
# @param block [Proc, nil] An optional block that will be instance-eval'd
|
66
|
+
# in the context of the new {Text} message instance. This can be used
|
67
|
+
# to add a quick reply to the text message.
|
68
|
+
# @return [Text] The newly created {Text} message object.
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# root.text "Hello, world!" do
|
72
|
+
# quick_reply do
|
73
|
+
# button action: :message, label: "Hi!", text: "Hi!"
|
74
|
+
# end
|
75
|
+
# end
|
16
76
|
def text(text, **options, &)
|
17
77
|
@messages << Text.new(text, context: context, **options, &)
|
18
78
|
end
|
19
79
|
|
80
|
+
# Creates a new {Flex::Builder} for constructing a Flex Message and adds it
|
81
|
+
# to this container. The block is mandatory and is used to define the
|
82
|
+
# content of the Flex Message using the Flex Message DSL.
|
83
|
+
#
|
84
|
+
# @param options [Hash] Options for the Flex Message, primarily `:alt_text`.
|
85
|
+
# See {Flex::Builder#initialize}. It's important to provide `alt_text`.
|
86
|
+
# @param block [Proc] A block that will be instance-eval'd in the context
|
87
|
+
# of the new {Flex::Builder} instance. This block is used to define the
|
88
|
+
# structure and content of the Flex Message (e.g., bubbles, carousels).
|
89
|
+
# @return [Flex::Builder] The newly created {Flex::Builder} object.
|
90
|
+
# @raise [ArgumentError] if `alt_text` is not provided in options (validation
|
91
|
+
# is typically within Flex::Builder).
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# flex alt_text: "Important information" do
|
95
|
+
# bubble do
|
96
|
+
# header { text "Header" }
|
97
|
+
# body { text "Body" }
|
98
|
+
# end
|
99
|
+
# end
|
20
100
|
def flex(**options, &)
|
21
101
|
@messages << Flex::Builder.new(context: context, **options, &)
|
22
102
|
end
|
23
103
|
|
104
|
+
# Converts all messages held by this container into their hash representations.
|
105
|
+
# This method iterates over each message object (e.g., {Text}, {Flex::Builder})
|
106
|
+
# stored in the container and calls its `to_h` method. The result is an
|
107
|
+
# array of hashes, where each hash represents a single LINE message object
|
108
|
+
# ready for JSON serialization and sending to the LINE Messaging API.
|
109
|
+
#
|
110
|
+
# @return [Array<Hash>] An array of message objects, each represented as a hash.
|
111
|
+
# This is the format expected by the LINE API for the `messages` field
|
112
|
+
# in a request body.
|
24
113
|
def build
|
25
114
|
@messages.map(&:to_h)
|
26
115
|
end
|
27
116
|
|
117
|
+
# Converts the array of message hashes (obtained from {#build}) into a
|
118
|
+
# JSON string. This is a convenience method for serializing the messages
|
119
|
+
# payload.
|
120
|
+
#
|
121
|
+
# @param args [Object] Optional arguments that are passed along to `to_json`
|
122
|
+
# method of the underlying array.
|
123
|
+
# @return [String] A JSON string representing the array of message objects.
|
28
124
|
def to_json(*args)
|
29
125
|
build.to_json(*args)
|
30
126
|
end
|
127
|
+
|
128
|
+
# Checks if a method is defined in the context object.
|
129
|
+
# This is part of Ruby's method_missing mechanism.
|
130
|
+
#
|
131
|
+
# @param method_name [Symbol] The name of the method being checked
|
132
|
+
# @param include_private [Boolean] Whether to include private methods
|
133
|
+
# @return [Boolean] True if the method exists in the context, false otherwise
|
134
|
+
def respond_to_missing?(method_name, include_private = false)
|
135
|
+
context.respond_to?(method_name, include_private) || super
|
136
|
+
end
|
137
|
+
|
138
|
+
# Delegates method calls to the context object if they exist there.
|
139
|
+
# This allows helper methods defined in the context to be called directly
|
140
|
+
# from within the builder DSL.
|
141
|
+
#
|
142
|
+
# @param method_name [Symbol] The name of the method being called
|
143
|
+
# @param args [Array] The arguments passed to the method
|
144
|
+
# @return [Object] The result of calling the method on the context
|
145
|
+
# @raise [NoMethodError] If the method doesn't exist in the context
|
146
|
+
def method_missing(method_name, ...)
|
147
|
+
return context.send(method_name, ...) if context.respond_to?(method_name)
|
148
|
+
|
149
|
+
super
|
150
|
+
end
|
31
151
|
end
|
32
152
|
end
|
33
153
|
end
|
@@ -3,27 +3,135 @@
|
|
3
3
|
module Line
|
4
4
|
module Message
|
5
5
|
module Builder
|
6
|
-
# The
|
6
|
+
# The `Context` class is a crucial component of the `Line::Message::Builder`
|
7
|
+
# DSL, enabling a flexible and dynamic environment for message construction.
|
8
|
+
# It acts as a wrapper around an optional user-provided context object and
|
9
|
+
# manages a separate hash of "assigns" (local variables for the DSL).
|
10
|
+
#
|
11
|
+
# The primary purposes of the `Context` are:
|
12
|
+
# 1. **To provide access to helper methods**: If a user passes a context object
|
13
|
+
# (e.g., a Rails view context, a presenter, or any custom object) during
|
14
|
+
# builder initialization (`Line::Message::Builder.with(my_helper_object)`),
|
15
|
+
# methods defined on `my_helper_object` become directly callable within
|
16
|
+
# the DSL blocks.
|
17
|
+
# 2. **To allow local data storage (`assigns`)**: The `assigns` hash allows
|
18
|
+
# for setting and retrieving temporary data that can be shared across
|
19
|
+
# different parts of a complex message construction block, without needing
|
20
|
+
# to pass it explicitly or pollute the user-provided context.
|
21
|
+
#
|
22
|
+
# Method calls within the DSL that are not defined on the builder objects
|
23
|
+
# themselves are resolved by `Context` in the following order:
|
24
|
+
# - First, it checks if the method name corresponds to a key in the `assigns` hash.
|
25
|
+
# - If not found in `assigns`, it checks if the wrapped user-context object
|
26
|
+
# responds to the method.
|
27
|
+
# - If neither, the call proceeds up the normal Ruby method lookup chain.
|
28
|
+
#
|
29
|
+
# This mechanism allows for a clean and powerful way to integrate external logic
|
30
|
+
# and data into the message building process.
|
31
|
+
#
|
32
|
+
# @example Using a custom context
|
33
|
+
# class MyContext
|
34
|
+
# def current_user_name
|
35
|
+
# "Alice"
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# context = MyContext.new
|
40
|
+
# Line::Message::Builder.with(context) do
|
41
|
+
# # `current_user_name` is resolved from `context` by Context
|
42
|
+
# text "Hello, #{current_user_name}!"
|
43
|
+
# end
|
7
44
|
class Context
|
45
|
+
# @!attribute assigns
|
46
|
+
# A hash for storing arbitrary data that can be accessed within the
|
47
|
+
# builder DSL. This is useful for temporary variables or shared state
|
48
|
+
# during message construction.
|
49
|
+
# @return [Hash] The hash of assigned values.
|
50
|
+
# @example
|
51
|
+
# context.assigns[:user_id] = 123
|
52
|
+
# puts context.assigns[:user_id] # => 123
|
8
53
|
attr_accessor :assigns
|
9
54
|
|
10
|
-
|
55
|
+
# @!attribute [r] mode
|
56
|
+
# The mode in which the builder is operating. This affects how messages
|
57
|
+
# are formatted in the final output.
|
58
|
+
# @return [Symbol] Either `:api` for direct LINE Messaging API format
|
59
|
+
# or `:sdkv2` for LINE Bot SDK v2 compatible format.
|
60
|
+
attr_reader :mode
|
61
|
+
|
62
|
+
# Initializes a new Context object.
|
63
|
+
#
|
64
|
+
# @param context [Object, nil] An optional object whose methods will be made
|
65
|
+
# available within the DSL. If `nil`, only `assigns` and standard
|
66
|
+
# builder methods will be available.
|
67
|
+
# @param mode [Symbol] The mode of the context, which can be `:api` (default)
|
68
|
+
# for direct LINE Messaging API format or `:sdkv2` for LINE Bot SDK v2
|
69
|
+
# compatible format.
|
70
|
+
def initialize(context, mode: :api)
|
11
71
|
@context = context
|
12
72
|
@assigns = {}
|
73
|
+
@mode = mode
|
13
74
|
end
|
14
75
|
|
76
|
+
# Part of Ruby's dynamic method dispatch. It's overridden here to declare
|
77
|
+
# that instances of `Context` can respond to methods that are either:
|
78
|
+
# 1. Keys in the `@assigns` hash.
|
79
|
+
# 2. Methods to which the wrapped `@context` object responds.
|
80
|
+
#
|
81
|
+
# This ensures that `respond_to?` behaves consistently with how
|
82
|
+
# `method_missing` resolves method calls.
|
83
|
+
#
|
84
|
+
# @param method_name [Symbol] The name of the method being queried.
|
85
|
+
# @param include_private [Boolean] Whether to include private methods in
|
86
|
+
# the check.
|
87
|
+
# @return [Boolean] `true` if the context can handle the method,
|
88
|
+
# `false` otherwise.
|
89
|
+
# @!visibility private
|
15
90
|
def respond_to_missing?(method_name, include_private = false)
|
16
91
|
@assigns.key?(method_name) ||
|
17
|
-
@context.respond_to?(method_name, include_private) ||
|
92
|
+
@context.respond_to?(method_name, include_private) || # Check @context directly
|
18
93
|
super
|
19
94
|
end
|
20
95
|
|
96
|
+
# Handles calls to methods not explicitly defined on the `Context` class.
|
97
|
+
# The resolution order is:
|
98
|
+
# 1. If `method_name` is a key in the `@assigns` hash, its value is returned.
|
99
|
+
# 2. If the wrapped `@context` object responds to `method_name`, the call
|
100
|
+
# is delegated to `@context`.
|
101
|
+
# 3. Otherwise, `super` is called, allowing the standard Ruby method
|
102
|
+
# lookup to continue (which will likely result in a `NoMethodError`
|
103
|
+
# if the method is truly undefined).
|
104
|
+
#
|
105
|
+
# This is the core mechanism that allows DSL blocks to seamlessly access
|
106
|
+
# data from `assigns` or methods from the user-provided context.
|
107
|
+
#
|
108
|
+
# @param method_name [Symbol] The name of the invoked method.
|
109
|
+
# @param ... [Object] Arguments passed to the method.
|
110
|
+
# @return [Object, nil] The value from `@assigns`, the result of the
|
111
|
+
# delegated call to `@context`, or raises `NoMethodError` via `super`.
|
112
|
+
# @raise [NoMethodError] If the method is not found in `assigns` or
|
113
|
+
# on the wrapped context.
|
114
|
+
# @!visibility private
|
21
115
|
def method_missing(method_name, ...)
|
22
116
|
return @assigns[method_name] if @assigns.key?(method_name)
|
117
|
+
# Check @context directly
|
23
118
|
return @context.public_send(method_name, ...) if @context.respond_to?(method_name)
|
24
119
|
|
25
120
|
super
|
26
121
|
end
|
122
|
+
|
123
|
+
# Checks if the current mode is set to SDK v2 compatibility.
|
124
|
+
#
|
125
|
+
# @return [Boolean] `true` if the mode is `:sdkv2`, `false` otherwise.
|
126
|
+
# @example
|
127
|
+
# if context.sdkv2?
|
128
|
+
# # Format message for LINE Bot SDK v2
|
129
|
+
# else
|
130
|
+
# # Format message for direct API use
|
131
|
+
# end
|
132
|
+
def sdkv2?
|
133
|
+
mode == :sdkv2
|
134
|
+
end
|
27
135
|
end
|
28
136
|
end
|
29
137
|
end
|
@@ -4,16 +4,61 @@ module Line
|
|
4
4
|
module Message
|
5
5
|
module Builder
|
6
6
|
module Flex
|
7
|
-
# The
|
7
|
+
# The `Actionable` module provides a DSL for defining an action that can be
|
8
|
+
# triggered when a user interacts with certain Flex Message components
|
9
|
+
# (e.g., a {Button} component, or an entire {Bubble} or {Box} component
|
10
|
+
# if it's made tappable).
|
11
|
+
#
|
12
|
+
# When a component includes this module, it gains methods like {#message}
|
13
|
+
# and {#postback} to associate a specific LINE action with itself. The
|
14
|
+
# chosen action is stored in the `action` attribute.
|
15
|
+
#
|
16
|
+
# @!attribute [r] action
|
17
|
+
# @return [Actions::Message, Actions::Postback, nil] The action object
|
18
|
+
# associated with this component. `nil` if no action is defined.
|
19
|
+
#
|
20
|
+
# @see Line::Message::Builder::Actions::Message
|
21
|
+
# @see Line::Message::Builder::Actions::Postback
|
22
|
+
# @see https://developers.line.biz/en/reference/messaging-api/#action-objects
|
8
23
|
module Actionable
|
24
|
+
# @!visibility private
|
25
|
+
# Automatically adds an `attr_reader :action` to the class that includes
|
26
|
+
# this module.
|
27
|
+
# @param base [Class] The class including this module.
|
9
28
|
def self.included(base)
|
10
29
|
base.attr_reader :action
|
11
30
|
end
|
12
31
|
|
32
|
+
# Defines a message action for the component.
|
33
|
+
# When the component is tapped, a message with the given `text` is sent
|
34
|
+
# from the user to the chat.
|
35
|
+
#
|
36
|
+
# @param text [String] The text of the message to send.
|
37
|
+
# @param options [Hash] Additional options for the message action,
|
38
|
+
# such as `:label`. See {Actions::Message#initialize}.
|
39
|
+
# @param block [Proc, nil] An optional block, though not typically used
|
40
|
+
# directly for message actions here.
|
41
|
+
# @return [Actions::Message] The created message action object.
|
42
|
+
#
|
43
|
+
# @example Setting a message action on a button
|
44
|
+
# button_component.message "Hello User!", label: "Send Greeting"
|
13
45
|
def message(text, **options, &)
|
14
46
|
@action = Actions::Message.new(text, context: context, **options, &)
|
15
47
|
end
|
16
48
|
|
49
|
+
# Defines a postback action for the component.
|
50
|
+
# When the component is tapped, a postback event with the given `data`
|
51
|
+
# is sent to the bot's webhook.
|
52
|
+
#
|
53
|
+
# @param data [String] The data payload for the postback event.
|
54
|
+
# @param options [Hash] Additional options for the postback action,
|
55
|
+
# such as `:label` or `:display_text`. See {Actions::Postback#initialize}.
|
56
|
+
# @param block [Proc, nil] An optional block, though not typically used
|
57
|
+
# directly for postback actions here.
|
58
|
+
# @return [Actions::Postback] The created postback action object.
|
59
|
+
#
|
60
|
+
# @example Setting a postback action on a button
|
61
|
+
# button_component.postback "action=buy&item_id=123", label: "Buy Item"
|
17
62
|
def postback(data, **options, &)
|
18
63
|
@action = Actions::Postback.new(data, context: context, **options, &)
|
19
64
|
end
|
@@ -4,66 +4,206 @@ module Line
|
|
4
4
|
module Message
|
5
5
|
module Builder
|
6
6
|
module Flex
|
7
|
-
#
|
7
|
+
# Represents a "box" component in a LINE Flex Message.
|
8
|
+
#
|
9
|
+
# A box is a fundamental layout container that arranges its child components
|
10
|
+
# (`contents`) in a specified direction (`layout`: horizontal, vertical, or
|
11
|
+
# baseline). It can hold various other components like text, images, buttons,
|
12
|
+
# or even nested boxes, allowing for complex layouts.
|
13
|
+
#
|
14
|
+
# Boxes have numerous properties to control their appearance and the
|
15
|
+
# arrangement of their children, such as padding, margin, spacing between
|
16
|
+
# items, justification, and alignment.
|
17
|
+
#
|
18
|
+
# A box can also have an `action` associated with it, making the entire
|
19
|
+
# box area tappable.
|
20
|
+
#
|
21
|
+
# @example Creating a horizontal box with two text components
|
22
|
+
# Line::Message::Builder.with do
|
23
|
+
# flex alt_text: "Box example" do
|
24
|
+
# bubble do
|
25
|
+
# body do
|
26
|
+
# layout :horizontal
|
27
|
+
# spacing :md
|
28
|
+
# text "Item 1"
|
29
|
+
# text "Item 2"
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# @see https://developers.line.biz/en/reference/messaging-api/#box
|
36
|
+
# @see Actionable For making the box tappable.
|
37
|
+
# @see HasPartial For including reusable component groups.
|
38
|
+
# @see Position::Padding For padding properties.
|
39
|
+
# @see Position::Margin For margin properties.
|
40
|
+
# @see Position::Offset For offset properties.
|
41
|
+
# @see Size::Flex For flex sizing property.
|
8
42
|
class Box < Line::Message::Builder::Base
|
9
|
-
include HasPartial
|
10
|
-
include Actionable
|
11
|
-
include Position::Padding
|
12
|
-
include Position::Margin
|
13
|
-
include Position::Offset
|
14
|
-
include Size::Flex
|
43
|
+
include HasPartial # Allows including predefined partial component sets.
|
44
|
+
include Actionable # Enables defining an action for the entire box.
|
45
|
+
include Position::Padding # Adds padding options like `padding_all`, `padding_top`, etc.
|
46
|
+
include Position::Margin # Adds `margin` option.
|
47
|
+
include Position::Offset # Adds offset options like `offset_top`, `offset_start`, etc.
|
48
|
+
include Size::Flex # Adds `flex` option for controlling size within a parent box.
|
15
49
|
|
50
|
+
# @!attribute [r] contents
|
51
|
+
# @return [Array<Base>] An array holding the child components (e.g.,
|
52
|
+
# {Text}, {Image}, nested {Box} instances) of this box.
|
16
53
|
attr_reader :contents
|
17
54
|
|
55
|
+
# Specifies the arrangement of child components.
|
56
|
+
# @!method layout(value)
|
57
|
+
# @param value [Symbol] `:horizontal` (default), `:vertical`, or `:baseline`.
|
58
|
+
# @return [Symbol] The current layout.
|
18
59
|
option :layout, default: :horizontal, validator: Validators::Enum.new(
|
19
60
|
:horizontal, :vertical, :baseline
|
20
61
|
)
|
62
|
+
|
63
|
+
# Horizontal alignment of content in a horizontal box; vertical alignment in a vertical box.
|
64
|
+
# @!method justify_content(value)
|
65
|
+
# @param value [Symbol, nil] E.g., `:flex_start`, `:center`, `:flex_end`,
|
66
|
+
# `:space_between`, `:space_around`, `:space_evenly`.
|
67
|
+
# @return [Symbol, nil] The current justify_content value.
|
21
68
|
option :justify_content, default: nil, validator: Validators::Enum.new(
|
22
69
|
:flex_start, :center, :flex_end, :space_between, :space_around, :space_evenly
|
23
70
|
)
|
71
|
+
|
72
|
+
# Vertical alignment of content in a horizontal box; horizontal alignment in a vertical box.
|
73
|
+
# @!method align_items(value)
|
74
|
+
# @param value [Symbol, nil] E.g., `:flex_start`, `:center`, `:flex_end`.
|
75
|
+
# @return [Symbol, nil] The current align_items value.
|
24
76
|
option :align_items, default: nil, validator: Validators::Enum.new(
|
25
77
|
:flex_start, :center, :flex_end
|
26
78
|
)
|
79
|
+
|
80
|
+
# Specifies the minimum spacing between components.
|
81
|
+
# Not applicable if `layout` is `:baseline` or if the box contains only one component.
|
82
|
+
# @!method spacing(value)
|
83
|
+
# @param value [String, Symbol, nil] E.g., `"md"`, `:lg`, `"10px"`.
|
84
|
+
# Keywords: `:none`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`.
|
85
|
+
# @return [String, Symbol, nil] The current spacing value.
|
27
86
|
option :spacing, default: nil, validator: Validators::Size.new(:pixel, :keyword)
|
87
|
+
|
88
|
+
# Width of the box. Can be a percentage or pixel value.
|
89
|
+
# @!method width(value)
|
90
|
+
# @param value [String, nil] E.g., `"100px"`, `"50%"`.
|
91
|
+
# @return [String, nil] The current width.
|
28
92
|
option :width, default: nil, validator: Validators::Size.new(:pixel, :percentage)
|
93
|
+
|
94
|
+
# Maximum width of the box.
|
95
|
+
# @!method max_width(value)
|
96
|
+
# @param value [String, nil] E.g., `"100px"`, `"50%"`.
|
97
|
+
# @return [String, nil] The current maximum width.
|
29
98
|
option :max_width, default: nil, validator: Validators::Size.new(:pixel, :percentage)
|
99
|
+
|
100
|
+
# Height of the box.
|
101
|
+
# @!method height(value)
|
102
|
+
# @param value [String, nil] E.g., `"100px"`, `"50%"`.
|
103
|
+
# @return [String, nil] The current height.
|
30
104
|
option :height, default: nil, validator: Validators::Size.new(:pixel, :percentage)
|
105
|
+
|
106
|
+
# Maximum height of the box.
|
107
|
+
# @!method max_height(value)
|
108
|
+
# @param value [String, nil] E.g., `"100px"`, `"50%"`.
|
109
|
+
# @return [String, nil] The current maximum height.
|
31
110
|
option :max_height, default: nil, validator: Validators::Size.new(:pixel, :percentage)
|
32
111
|
|
112
|
+
# Initializes a new Flex Message Box component.
|
113
|
+
# The provided block is instance-eval'd, allowing DSL methods for adding
|
114
|
+
# child components (e.g., {#text}, {#button}, nested {#box}) to be called.
|
115
|
+
#
|
116
|
+
# @param context [Object, nil] An optional context for the builder.
|
117
|
+
# @param options [Hash] A hash of options to set instance variables.
|
118
|
+
# Corresponds to the `option` definitions in this class and included modules.
|
119
|
+
# @param block [Proc, nil] A block to define the contents of this box.
|
33
120
|
def initialize(context: nil, **options, &)
|
34
|
-
@contents = []
|
35
|
-
|
36
|
-
super
|
121
|
+
@contents = [] # Holds child components
|
122
|
+
super # Calls Base#initialize, sets options, and evals block
|
37
123
|
end
|
38
124
|
|
125
|
+
# Adds a nested Flex {Box} component to this box's contents.
|
126
|
+
#
|
127
|
+
# @param options [Hash] Options for the nested box. See {Box#initialize}.
|
128
|
+
# @param block [Proc] A block to define the contents of the nested box.
|
129
|
+
# @return [Flex::Box] The newly created nested Box object.
|
39
130
|
def box(**options, &)
|
40
131
|
@contents << Flex::Box.new(context: context, **options, &)
|
41
132
|
end
|
42
133
|
|
43
|
-
|
134
|
+
# Adds a Flex {Text} component to this box's contents.
|
135
|
+
#
|
136
|
+
# @param text [String] The text content.
|
137
|
+
# @param options [Hash] Options for the text component. See {Text#initialize}.
|
138
|
+
# @param block [Proc, nil] An optional block for the text component. This can be used
|
139
|
+
# to define an action for the text or to add {Span} components within the text.
|
140
|
+
# @return [Flex::Text] The newly created Text object.
|
141
|
+
# @example Simple text component
|
142
|
+
# text "Hello, World!"
|
143
|
+
# @example Text with an action
|
144
|
+
# text "Click me" do
|
145
|
+
# message "Action", text: "You clicked me!"
|
146
|
+
# end
|
147
|
+
# @example Text with spans
|
148
|
+
# text "This has " do
|
149
|
+
# span "styled", color: "#FF0000"
|
150
|
+
# span " parts"
|
151
|
+
# end
|
152
|
+
def text(text = nil, **options, &)
|
44
153
|
@contents << Flex::Text.new(text, context: context, **options, &)
|
45
154
|
end
|
46
155
|
|
156
|
+
# Adds a Flex {Button} component to this box's contents.
|
157
|
+
#
|
158
|
+
# @param options [Hash] Options for the button component. See {Button#initialize}.
|
159
|
+
# @param block [Proc] A block to define the button's action and properties.
|
160
|
+
# @return [Flex::Button] The newly created Button object.
|
47
161
|
def button(**options, &)
|
48
162
|
@contents << Flex::Button.new(context: context, **options, &)
|
49
163
|
end
|
50
164
|
|
165
|
+
# Adds a Flex {Image} component to this box's contents.
|
166
|
+
#
|
167
|
+
# @param url [String] The URL of the image.
|
168
|
+
# @param options [Hash] Options for the image component. See {Image#initialize}.
|
169
|
+
# @param block [Proc, nil] An optional block for the image component (e.g., for an action).
|
170
|
+
# @return [Flex::Image] The newly created Image object.
|
51
171
|
def image(url, **options, &)
|
52
172
|
@contents << Flex::Image.new(url, context: context, **options, &)
|
53
173
|
end
|
54
174
|
|
55
|
-
|
175
|
+
# Adds a Flex {Separator} component to this box's contents.
|
176
|
+
#
|
177
|
+
# A separator is a simple component that draws a horizontal line,
|
178
|
+
# creating a visual division between other components in a container.
|
179
|
+
#
|
180
|
+
# @param options [Hash] Options for the separator component. See {Separator}.
|
181
|
+
# @param block [Proc, nil] An optional block for advanced separator configuration.
|
182
|
+
# @return [Flex::Separator] The newly created Separator object.
|
183
|
+
def separator(**options, &)
|
184
|
+
@contents << Flex::Separator.new(context: context, **options, &)
|
185
|
+
end
|
186
|
+
|
187
|
+
def to_h
|
56
188
|
raise RequiredError, "layout is required" if layout.nil?
|
57
189
|
|
190
|
+
return to_sdkv2 if context.sdkv2?
|
191
|
+
|
192
|
+
to_api
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
|
197
|
+
def to_api # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
58
198
|
{
|
59
199
|
type: "box",
|
60
200
|
layout: layout,
|
61
|
-
# Position
|
201
|
+
# Position & Layout
|
62
202
|
justifyContent: justify_content,
|
63
203
|
alignItems: align_items,
|
64
204
|
spacing: spacing,
|
65
205
|
# Position::Padding
|
66
|
-
paddingAll: padding,
|
206
|
+
paddingAll: padding || padding_all,
|
67
207
|
paddingTop: padding_top,
|
68
208
|
paddingBottom: padding_bottom,
|
69
209
|
paddingStart: padding_start,
|
@@ -83,8 +223,44 @@ module Line
|
|
83
223
|
maxHeight: max_height,
|
84
224
|
# Size::Flex
|
85
225
|
flex: flex,
|
226
|
+
# Contents & Action
|
227
|
+
contents: contents.map(&:to_h),
|
228
|
+
action: action&.to_h # From Actionable module
|
229
|
+
}.compact
|
230
|
+
end
|
231
|
+
|
232
|
+
def to_sdkv2 # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
233
|
+
{
|
234
|
+
type: "box",
|
235
|
+
layout: layout,
|
236
|
+
# Position & Layout
|
237
|
+
justify_content: justify_content,
|
238
|
+
align_items: align_items,
|
239
|
+
spacing: spacing,
|
240
|
+
# Position::Padding
|
241
|
+
padding_all: padding || padding_all,
|
242
|
+
padding_top: padding_top,
|
243
|
+
padding_bottom: padding_bottom,
|
244
|
+
padding_start: padding_start,
|
245
|
+
padding_end: padding_end,
|
246
|
+
# Position::Margin
|
247
|
+
margin: margin,
|
248
|
+
# Position::Offset
|
249
|
+
position: position,
|
250
|
+
offset_top: offset_top,
|
251
|
+
offset_bottom: offset_bottom,
|
252
|
+
offset_start: offset_start,
|
253
|
+
offset_end: offset_end,
|
254
|
+
# Size
|
255
|
+
width: width,
|
256
|
+
max_width: max_width,
|
257
|
+
height: height,
|
258
|
+
max_height: max_height,
|
259
|
+
# Size::Flex
|
260
|
+
flex: flex,
|
261
|
+
# Contents & Action
|
86
262
|
contents: contents.map(&:to_h),
|
87
|
-
action: action&.to_h
|
263
|
+
action: action&.to_h # From Actionable module
|
88
264
|
}.compact
|
89
265
|
end
|
90
266
|
end
|