Skip to content

Commit e07f2a2

Browse files
committed
array input
1 parent 8c94484 commit e07f2a2

File tree

6 files changed

+93
-76
lines changed

6 files changed

+93
-76
lines changed

assets/css/default_overrides.css

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@
311311
opacity:.5;
312312
background-color: darkgray;
313313
border:0;
314+
pointer-events: none;
314315
}
315316

316317
input[class$='loading'] + .select-options {
@@ -320,3 +321,46 @@
320321
button[class$='loading'] {
321322
opacity:.5;
322323
}
324+
325+
326+
.array-input-wrapper {
327+
border: 1px solid #e2e8f0;
328+
border-radius: 8px;
329+
padding: 2px;
330+
display: flex;
331+
flex-wrap: wrap;
332+
gap: 8px;
333+
min-height: 39px;
334+
transition: border-color 0.2s;
335+
}
336+
337+
.array-input-wrapper:focus-within {
338+
border-color: var(--accent-color);
339+
background: white;
340+
}
341+
342+
.array-input-wrapper .btn {
343+
height:32px;
344+
padding: 0 10px;
345+
}
346+
347+
@keyframes slideIn {
348+
from {
349+
opacity: 0;
350+
transform: scale(0.8);
351+
}
352+
to {
353+
opacity: 1;
354+
transform: scale(1);
355+
}
356+
}
357+
358+
.array-input-wrapper input {
359+
border: none;
360+
outline: none;
361+
flex: 1;
362+
min-width: 120px;
363+
font-size: 14px;
364+
padding: 6px;
365+
background: transparent;
366+
}

assets/js/app.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,18 @@ Hooks.SearchSelect = {
8888

8989
Hooks.ArrayInput = {
9090
mounted() {
91-
this.handleEvent("change", () => {
92-
this.el
93-
.querySelector("input")
94-
.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
95-
});
91+
this.el.querySelector("input").addEventListener("input", e => e.stopPropagation());
92+
93+
this.el.addEventListener("keydown", e => {
94+
if (e.key === "Enter") {
95+
e.target.blur()
96+
e.preventDefault();
97+
}
98+
});
9699
},
100+
updated() {
101+
this.el.querySelector("input").addEventListener("input", e => e.stopPropagation());
102+
}
97103
};
98104

99105
Hooks.MapInput = {

dist/css/default_overrides.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/js/app.js

Lines changed: 10 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/live_admin/components/resource/form.ex

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ defmodule LiveAdmin.Components.Container.Form do
6767
phx-target={@myself}
6868
class="form-grid"
6969
>
70-
<%= for {field, type, opts} <- Resource.fields(@resource, @config), f.data |> Ecto.primary_key() |> Keyword.keys() |> Enum.member?(field) |> Kernel.not() do %>
70+
<%= for {field, type, opts} <- Resource.fields(@resource, @config), editable_inline?(f, field, type) do %>
7171
<div class="form-field">
7272
<div class="form-label">
7373
{label(f, field, field |> humanize() |> trans())}
@@ -118,19 +118,14 @@ defmodule LiveAdmin.Components.Container.Form do
118118
"""
119119
end
120120

121-
# <div class="detail-section">
122-
# <div class="form-field">
123-
# <label class="form-label" for="edit-description">Description</label>
124-
# <textarea id="edit-description" class="form-textarea">This task involves designing and implementing the complete database schema for Project Alpha. The schema has been optimized for performance and scalability, incorporating best practices for data normalization and indexing strategies.</textarea>
125-
# </div>
126-
# </div>
121+
defp editable_inline?(form, field, type) when type in [:id, :binary_id],
122+
do: form.data |> Ecto.primary_key() |> Keyword.keys() |> Enum.member?(field) |> Kernel.not()
127123

128-
# <div class="detail-section">
129-
# <div class="form-field">
130-
# <label class="form-label" for="edit-notes">Notes</label>
131-
# <textarea id="edit-notes" class="form-textarea">Schema optimized - All tables have been reviewed and optimized. Foreign key relationships established. Indexes created for frequently queried columns. Migration scripts prepared for deployment.</textarea>
132-
# </div>
133-
# </div>
124+
defp editable_inline?(form, _, {_, {Ecto.Embedded, _}}), do: false
125+
126+
defp editable_inline?(form, _, :map), do: false
127+
128+
defp editable_inline?(_, _, _), do: true
134129

135130
@impl true
136131
def handle_event(
@@ -189,24 +184,6 @@ defmodule LiveAdmin.Components.Container.Form do
189184
{:noreply, socket}
190185
end
191186

192-
# defp input(assigns = %{type: {_, {Ecto.Embedded, _}}}) do
193-
# ~H"""
194-
# <.embed
195-
# id={input_id(@form, @field)}
196-
# type={@type}
197-
# disabled={@disabled}
198-
# form={@form}
199-
# field={@field}
200-
# resource={@resource}
201-
# resources={@resource}
202-
# session={@session}
203-
# prefix={@prefix}
204-
# repo={@repo}
205-
# config={@config}
206-
# />
207-
# """
208-
# end
209-
210187
defp input(assigns = %{type: id}) when id in [:id, :binary_id] do
211188
assigns =
212189
assign(
@@ -313,6 +290,18 @@ defmodule LiveAdmin.Components.Container.Form do
313290
"""
314291
end
315292

293+
defp input(assigns = %{type: {:array, :string}}) do
294+
~H"""
295+
<.live_component
296+
module={ArrayInput}
297+
id={input_id(@form, @field)}
298+
form={@form}
299+
field={@field}
300+
disabled={@disabled}
301+
/>
302+
"""
303+
end
304+
316305
defp input(assigns = %{type: :date}) do
317306
~H"""
318307
<input type="date" class="form-input" name={@form[@field].name} value={@form[@field].value} />

lib/live_admin/components/resource/form/array_input.ex

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -38,49 +38,20 @@ defmodule LiveAdmin.Components.Container.Form.ArrayInput do
3838
@impl true
3939
def render(assigns) do
4040
~H"""
41-
<div
42-
class="field__array--group"
43-
phx-hook="ArrayInput"
44-
id={input_id(@form, @field) <> "_array_input"}
45-
>
41+
<div class="array-input-wrapper" phx-hook="ArrayInput" id={@form[@field].id <> "_array_input"}>
4642
<%= for {item, idx} <- Enum.with_index(@values) do %>
47-
<div>
48-
<a
49-
href="#"
50-
class="button__remove"
51-
phx-click={
52-
JS.push("remove",
53-
value: %{idx: idx},
54-
target: @myself,
55-
page_loading: true
56-
)
57-
}
58-
/>
59-
{text_input(:form, :array,
60-
id: input_id(@form, @field) <> "_#{idx}",
61-
name: input_name(@form, @field) <> "[]",
62-
value: item,
63-
phx_debounce: 200
64-
)}
65-
</div>
43+
<button type="button" class="btn" phx-click={JS.push("remove", value: %{idx: idx}, target: @myself)}>
44+
{item}
45+
</button>
6646
<% end %>
67-
<a
68-
href="#"
69-
phx-click={
70-
JS.push("add",
71-
target: @myself,
72-
page_loading: true
73-
)
74-
}
75-
class="button__add"
76-
/>
47+
<input type="text" autocomplete="off" phx-keydown="add" phx-key="Enter" phx-target={@myself} />
7748
</div>
7849
"""
7950
end
8051

8152
@impl true
82-
def handle_event("add", _params, socket) do
83-
socket = assign(socket, values: socket.assigns.values ++ [""])
53+
def handle_event("add", %{"value" => item}, socket) do
54+
socket = assign(socket, values: socket.assigns.values ++ [item])
8455

8556
{:noreply, socket}
8657
end

0 commit comments

Comments
 (0)