Skip to content

Commit 47a2459

Browse files
committed
Added new range options to form and input
1 parent d4d1a7d commit 47a2459

File tree

2 files changed

+218
-2
lines changed

2 files changed

+218
-2
lines changed

lib/petal_components/form.ex

+100
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ defmodule PetalComponents.Form do
5959
"color_input",
6060
"file_input",
6161
"range_input",
62+
"range_dual",
63+
"range_numeric",
6264
"textarea",
6365
"select",
6466
"checkbox",
@@ -222,6 +224,86 @@ defmodule PetalComponents.Form do
222224
<% "range_input" -> %>
223225
<.form_label form={@form} field={@field} label={@label} class={@label_class} />
224226
<.range_input form={@form} field={@field} {@rest} />
227+
<% "range_dual" -> %>
228+
<.form_label form={@form} field={@field} label={@label} class={@label_class} />
229+
<div id={@id || Phoenix.HTML.Form.input_id(@form, @field)} class="relative h-12 mt-4">
230+
<div class="flex flex-row items-center justify-center space-x-2">
231+
<div class="relative w-full h-1">
232+
<div class="pc-slider-track"></div>
233+
<div
234+
class="pc-slider-range"
235+
data-slider-id={@id || Phoenix.HTML.Form.input_id(@form, @field)}
236+
id={@id || Phoenix.HTML.Form.input_id(@form, @field) <> "_slider-range"}
237+
style={"left: #{calculate_slider_position(@min_field.value, @range_min, @range_max)}%; right: #{100 - calculate_slider_position(@max_field.value, @range_min, @range_max)}%;"}
238+
>
239+
</div>
240+
<input
241+
type="range"
242+
min={@range_min}
243+
max={@range_max}
244+
step={@step}
245+
name={@min_field.name}
246+
value={@min_field.value}
247+
class="pc-slider-input"
248+
id={@id || Phoenix.HTML.Form.input_id(@form, @field) <> "_min-range"}
249+
phx-hook="DualRangeSliderHook"
250+
data-slider-id={@id || Phoenix.HTML.Form.input_id(@form, @field)}
251+
data-slider-type="min"
252+
data-range-min={@range_min}
253+
data-range-max={@range_max}
254+
/>
255+
<input
256+
type="range"
257+
min={@range_min}
258+
max={@range_max}
259+
step={@step}
260+
name={@max_field.name}
261+
value={@max_field.value}
262+
class="pc-slider-input"
263+
id={@id || Phoenix.HTML.Form.input_id(@form, @field) <> "_max-range"}
264+
phx-hook="DualRangeSliderHook"
265+
data-slider-id={@id || Phoenix.HTML.Form.input_id(@form, @field)}
266+
data-slider-type="max"
267+
data-range-min={@range_min}
268+
data-range-max={@range_max}
269+
/>
270+
</div>
271+
</div>
272+
# ... rest of the range slider code ...
273+
</div>
274+
<.form_field_error form={@form} field={@field} />
275+
<.form_help_text help_text={@help_text} />
276+
<% "range_numeric" -> %>
277+
<.form_label form={@form} field={@field} label={@label} class={@label_class} />
278+
<div class="flex flex-row gap-2">
279+
<.form_field
280+
type="number_input"
281+
form={@form}
282+
field={@min_field.name}
283+
label=""
284+
placeholder="No Min"
285+
min={@range_min}
286+
max={@max_field.value}
287+
value={@min_field.value}
288+
wrapper_classes="w-full"
289+
/>
290+
291+
<div class="flex flex-col items-center justify-center">-</div>
292+
293+
<.form_field
294+
type="number_input"
295+
form={@form}
296+
field={@max_field.name}
297+
label=""
298+
placeholder="No Max"
299+
min={@min_field.value}
300+
max={@range_max}
301+
value={@max_field.value}
302+
wrapper_classes="w-full"
303+
/>
304+
</div>
305+
<.form_field_error form={@form} field={@field} />
306+
<.form_help_text help_text={@help_text} />
225307
<% "textarea" -> %>
226308
<.form_label form={@form} field={@field} label={@label} class={@label_class} />
227309
<.textarea form={@form} field={@field} {@rest} />
@@ -785,6 +867,24 @@ defmodule PetalComponents.Form do
785867
"#{if errors != [], do: "has-error", else: ""} pc-range-input"
786868
end
787869

870+
# Helper functions for dual range slider
871+
defp calculate_slider_position(nil, _range_min, _range_max), do: 0
872+
873+
defp calculate_slider_position(value, range_min, range_max) when is_integer(value) do
874+
round((value - range_min) / (range_max - range_min) * 100)
875+
end
876+
877+
defp calculate_slider_position(value, range_min, range_max) do
878+
value =
879+
case value do
880+
v when is_binary(v) -> String.to_integer(v)
881+
v when is_integer(v) -> v
882+
_ -> range_min
883+
end
884+
885+
round((value - range_min) / (range_max - range_min) * 100)
886+
end
887+
788888
defp checkbox_classes(errors) do
789889
"#{if errors != [], do: "has-error", else: ""} pc-checkbox"
790890
end

lib/petal_components/input.ex

+118-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ defmodule PetalComponents.Input do
1313

1414
attr :type, :string,
1515
default: "text",
16-
values: ~w(checkbox color date datetime-local email file hidden month number password
17-
range radio search select switch tel text textarea time url week)
16+
values:
17+
~w(checkbox color date datetime-local email file hidden month number password
18+
range range-dual range-numeric radio search select switch tel text textarea time url week)
1819

1920
attr :size, :string, default: "md", values: ~w(xs sm md lg xl), doc: "the size of the switch"
2021

@@ -222,6 +223,98 @@ defmodule PetalComponents.Input do
222223
"""
223224
end
224225

226+
def input(%{type: "range-dual"} = assigns) do
227+
~H"""
228+
<div id={@id} class="relative h-12 mt-4">
229+
<div class="flex flex-row items-center justify-center space-x-2">
230+
<div class="relative w-full h-1">
231+
<div class="pc-slider-track"></div>
232+
<div
233+
class="pc-slider-range"
234+
data-slider-id={@id}
235+
id={@id <> "_slider-range"}
236+
style={"left: #{calculate_slider_position(@min_field.value, @range_min, @range_max)}%; right: #{100 - calculate_slider_position(@max_field.value, @range_min, @range_max)}%;"}
237+
>
238+
</div>
239+
<input
240+
type="range"
241+
min={@range_min}
242+
max={@range_max}
243+
step={@step}
244+
name={@min_field.name}
245+
value={@min_field.value}
246+
class="pc-slider-input"
247+
id={@id <> "_min-range"}
248+
phx-hook="DualRangeSliderHook"
249+
data-slider-id={@id}
250+
data-slider-type="min"
251+
data-range-min={@range_min}
252+
data-range-max={@range_max}
253+
/>
254+
<input
255+
type="range"
256+
min={@range_min}
257+
max={@range_max}
258+
step={@step}
259+
name={@max_field.name}
260+
value={@max_field.value}
261+
class="pc-slider-input"
262+
id={@id <> "_max-range"}
263+
phx-hook="DualRangeSliderHook"
264+
data-slider-id={@id}
265+
data-slider-type="max"
266+
data-range-min={@range_min}
267+
data-range-max={@range_max}
268+
/>
269+
</div>
270+
</div>
271+
<div class="grid grid-cols-3 mt-4 text-sm">
272+
<span class="flex items-start justify-start text-gray-500 dark:text-gray-400">
273+
{@range_min_label || @format_value.(@range_min)}
274+
</span>
275+
<span class="flex justify-center text-gray-600 dark:text-gray-300">
276+
{@format_value.(@min_field.value) <> " - " <> @format_value.(@max_field.value)}
277+
</span>
278+
<span class="flex items-end justify-end text-gray-500 dark:text-gray-400">
279+
{@range_max_label || @format_value.(@range_max)}
280+
</span>
281+
</div>
282+
</div>
283+
"""
284+
end
285+
286+
def input(%{type: "range-numeric"} = assigns) do
287+
~H"""
288+
<div class="flex flex-row gap-2">
289+
<input
290+
type="number"
291+
step={@step}
292+
name={@min_field.name}
293+
value={@min_field.value}
294+
placeholder="No Min"
295+
min={@range_min}
296+
max={@max_field.value}
297+
id={@id <> "_min"}
298+
inputmode="numeric"
299+
class="w-full pc-text-input"
300+
/>
301+
<div class="flex flex-col items-center justify-center">-</div>
302+
<input
303+
type="number"
304+
step={@step}
305+
name={@max_field.name}
306+
value={@max_field.value}
307+
placeholder="No Max"
308+
min={@min_field.value}
309+
max={@range_max}
310+
id={@id <> "_max"}
311+
inputmode="numeric"
312+
class="w-full pc-text-input"
313+
/>
314+
</div>
315+
"""
316+
end
317+
225318
def input(assigns) do
226319
~H"""
227320
<input
@@ -247,4 +340,27 @@ defmodule PetalComponents.Input do
247340
defp get_icon_for_type("month"), do: "hero-calendar"
248341
defp get_icon_for_type("week"), do: "hero-calendar"
249342
defp get_icon_for_type("time"), do: "hero-clock"
343+
344+
# Helper functions for input.ex
345+
defp calculate_slider_position(nil, _range_min, _range_max), do: 0
346+
347+
defp calculate_slider_position(value, range_min, range_max) when is_integer(value) do
348+
round((value - range_min) / (range_max - range_min) * 100)
349+
end
350+
351+
defp calculate_slider_position(value, range_min, range_max) do
352+
value =
353+
case value do
354+
v when is_binary(v) -> String.to_integer(v)
355+
v when is_integer(v) -> v
356+
_ -> range_min
357+
end
358+
359+
round((value - range_min) / (range_max - range_min) * 100)
360+
end
361+
362+
# Add format_value function
363+
defp format_value(value) when is_integer(value), do: Integer.to_string(value)
364+
defp format_value(value) when is_float(value), do: Float.to_string(value)
365+
defp format_value(_), do: "0"
250366
end

0 commit comments

Comments
 (0)