lightning_ui_kit 0.1.2 → 0.1.4
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/app/assets/builds/lightning_ui_kit.css +1813 -65
- data/app/assets/builds/lightning_ui_kit.js +2 -2
- data/app/assets/builds/lightning_ui_kit.js.map +4 -4
- data/app/assets/vendor/lightning_ui_kit.css +2883 -0
- data/app/assets/vendor/lightning_ui_kit.js +5 -0
- data/app/components/lightning_ui_kit/badge_component.rb +30 -5
- data/app/components/lightning_ui_kit/banner_component.rb +1 -1
- data/app/components/lightning_ui_kit/checkbox_component.html.erb +1 -1
- data/app/components/lightning_ui_kit/dropzone_component.html.erb +82 -0
- data/app/components/lightning_ui_kit/dropzone_component.rb +61 -0
- data/app/components/lightning_ui_kit/errors.rb +34 -0
- data/app/components/lightning_ui_kit/file_input_component.html.erb +50 -0
- data/app/components/lightning_ui_kit/file_input_component.rb +62 -0
- data/app/components/lightning_ui_kit/input_component.html.erb +40 -23
- data/app/components/lightning_ui_kit/input_component.rb +17 -2
- data/app/components/lightning_ui_kit/select_component.html.erb +23 -3
- data/app/components/lightning_ui_kit/select_component.rb +31 -1
- data/app/components/lightning_ui_kit/switch_component.html.erb +9 -2
- data/app/components/lightning_ui_kit/switch_component.rb +12 -1
- data/app/components/lightning_ui_kit/textarea_component.html.erb +17 -10
- data/app/components/lightning_ui_kit/textarea_component.rb +17 -2
- data/app/javascript/lightning_ui_kit/controllers/accordion_controller.js +11 -6
- data/app/javascript/lightning_ui_kit/controllers/dropzone_controller.js +79 -0
- data/app/javascript/lightning_ui_kit/index.js +5 -0
- data/config/locales/en.yml +3 -0
- data/lib/lightning_ui_kit/engine.rb +0 -1
- data/lib/lightning_ui_kit/version.rb +1 -1
- metadata +11 -2
@@ -2,12 +2,12 @@
|
|
2
2
|
class: classes,
|
3
3
|
data:
|
4
4
|
) do %>
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
<% if @label %>
|
6
|
+
<%= tag.label(
|
7
|
+
@label,
|
8
|
+
class: "text-base/6 text-zinc-950 select-none data-disabled:opacity-50 sm:text-sm/6",
|
9
|
+
data: label_data
|
10
|
+
) %>
|
11
11
|
<% end %>
|
12
12
|
<% if @description %>
|
13
13
|
<%= tag.p(
|
@@ -17,13 +17,13 @@
|
|
17
17
|
) %>
|
18
18
|
<% end %>
|
19
19
|
<% if @form %>
|
20
|
-
<span data-slot="control" class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm
|
20
|
+
<span data-slot="control" class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500 has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none has-data-invalid:before:shadow-red-500/10">
|
21
21
|
<% case @type %>
|
22
22
|
<% when :text %>
|
23
23
|
<%= @form.text_field(
|
24
24
|
@name,
|
25
25
|
data: input_data,
|
26
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
26
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500/60 data-disabled:border-zinc-950/20",
|
27
27
|
disabled: @disabled,
|
28
28
|
autofocus: @autofocus,
|
29
29
|
placeholder: @placeholder
|
@@ -32,68 +32,85 @@
|
|
32
32
|
<%= @form.email_field(
|
33
33
|
@name,
|
34
34
|
data: input_data,
|
35
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
35
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500/60 data-disabled:border-zinc-950/20",
|
36
36
|
disabled: @disabled,
|
37
|
-
autofocus: @autofocus
|
37
|
+
autofocus: @autofocus,
|
38
|
+
placeholder: @placeholder
|
38
39
|
) %>
|
39
40
|
<% when :password %>
|
40
41
|
<%= @form.password_field(
|
41
42
|
@name,
|
42
43
|
data: input_data,
|
43
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
44
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500/60 data-disabled:border-zinc-950/20",
|
44
45
|
disabled: @disabled,
|
45
|
-
autofocus: @autofocus
|
46
|
+
autofocus: @autofocus,
|
47
|
+
placeholder: @placeholder
|
46
48
|
) %>
|
47
49
|
<% when :number %>
|
48
50
|
<%= @form.number_field(
|
49
51
|
@name,
|
50
52
|
data: input_data,
|
51
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
53
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500/60 data-disabled:border-zinc-950/20",
|
52
54
|
disabled: @disabled,
|
53
|
-
autofocus: @autofocus
|
55
|
+
autofocus: @autofocus,
|
56
|
+
placeholder: @placeholder,
|
57
|
+
min: @options[:min],
|
58
|
+
max: @options[:max],
|
59
|
+
step: @options[:step]
|
54
60
|
) %>
|
55
61
|
<% end %>
|
56
62
|
</span>
|
57
63
|
<% else %>
|
58
|
-
<span data-slot="control" class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm
|
64
|
+
<span data-slot="control" class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500 has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none has-data-invalid:before:shadow-red-500/10">
|
59
65
|
<% case @type %>
|
60
66
|
<% when :text %>
|
61
67
|
<%= text_field_tag(
|
62
68
|
@name,
|
63
69
|
@value,
|
64
70
|
data: input_data,
|
65
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
71
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500/60 data-disabled:border-zinc-950/20",
|
66
72
|
disabled: @disabled,
|
67
|
-
autofocus: @autofocus
|
73
|
+
autofocus: @autofocus,
|
74
|
+
placeholder: @placeholder
|
68
75
|
) %>
|
69
76
|
<% when :email %>
|
70
77
|
<%= email_field_tag(
|
71
78
|
@name,
|
72
79
|
@value,
|
73
80
|
data: input_data,
|
74
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
81
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500/60 data-disabled:border-zinc-950/20",
|
75
82
|
disabled: @disabled,
|
76
|
-
autofocus: @autofocus
|
83
|
+
autofocus: @autofocus,
|
84
|
+
placeholder: @placeholder
|
77
85
|
) %>
|
78
86
|
<% when :password %>
|
79
87
|
<%= password_field_tag(
|
80
88
|
@name,
|
81
89
|
@value,
|
82
90
|
data: input_data,
|
83
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
91
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500/60 data-disabled:border-zinc-950/20",
|
84
92
|
disabled: @disabled,
|
85
|
-
autofocus: @autofocus
|
93
|
+
autofocus: @autofocus,
|
94
|
+
placeholder: @placeholder
|
86
95
|
) %>
|
87
96
|
<% when :number %>
|
88
97
|
<%= number_field_tag(
|
89
98
|
@name,
|
90
99
|
@value,
|
91
100
|
data: input_data,
|
92
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
101
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500/60 data-disabled:border-zinc-950/20",
|
93
102
|
disabled: @disabled,
|
94
|
-
autofocus: @autofocus
|
103
|
+
autofocus: @autofocus,
|
104
|
+
placeholder: @placeholder,
|
95
105
|
) %>
|
96
106
|
<% end %>
|
97
107
|
</span>
|
98
108
|
<% end %>
|
109
|
+
<% if has_errors? %>
|
110
|
+
<%= tag.p(
|
111
|
+
error_messages,
|
112
|
+
class: "text-base/6 text-red-600 data-disabled:opacity-50 sm:text-sm/6",
|
113
|
+
data: error_data
|
114
|
+
) %>
|
115
|
+
<% end %>
|
99
116
|
<% end %>
|
@@ -1,11 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class LightningUiKit::InputComponent < LightningUiKit::BaseComponent
|
4
|
-
|
4
|
+
include LightningUiKit::Errors
|
5
|
+
|
6
|
+
def initialize(name:, value: nil, autofocus: false, label: nil, form: nil, type: :text, description: nil, disabled: false, placeholder: nil, error: nil, **options)
|
5
7
|
@name = name
|
6
8
|
@value = value
|
7
9
|
@disabled = disabled
|
8
10
|
@autofocus = autofocus
|
11
|
+
@error = error
|
9
12
|
@label = label
|
10
13
|
@form = form
|
11
14
|
@type = type
|
@@ -23,7 +26,11 @@ class LightningUiKit::InputComponent < LightningUiKit::BaseComponent
|
|
23
26
|
end
|
24
27
|
|
25
28
|
def input_data
|
26
|
-
@options[:input_data] || {}
|
29
|
+
(@options[:input_data] || {}).tap do |data|
|
30
|
+
if has_errors?
|
31
|
+
data[:invalid] = "true"
|
32
|
+
end
|
33
|
+
end
|
27
34
|
end
|
28
35
|
|
29
36
|
def label_data
|
@@ -41,4 +48,12 @@ class LightningUiKit::InputComponent < LightningUiKit::BaseComponent
|
|
41
48
|
end
|
42
49
|
end
|
43
50
|
end
|
51
|
+
|
52
|
+
def error_data
|
53
|
+
{slot: "error"}.merge(@options[:error_data] || {}).tap do |data|
|
54
|
+
if @disabled
|
55
|
+
data[:disabled] = "true"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
44
59
|
end
|
@@ -9,12 +9,32 @@
|
|
9
9
|
<%= @description %>
|
10
10
|
</p>
|
11
11
|
<% end %>
|
12
|
-
<span data-slot="control"
|
12
|
+
<span data-slot="control"
|
13
|
+
class="group relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset focus:after:ring-2 focus:after:ring-blue-500 has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none">
|
13
14
|
<% if @form %>
|
14
|
-
<%= @form.select(
|
15
|
+
<%= @form.select(
|
16
|
+
@name,
|
17
|
+
@options_for_select,
|
18
|
+
{multiple: @multiple},
|
19
|
+
class: "relative block w-full appearance-none rounded-lg py-[calc(--spacing(2.5)-1px)] sm:py-[calc(--spacing(1.5)-1px)] pr-[calc(--spacing(10)-1px)] pl-[calc(--spacing(3.5)-1px)] sm:pr-[calc(--spacing(9)-1px)] sm:pl-[calc(--spacing(3)-1px)] [&_optgroup]:font-semibold text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500 data-disabled:border-zinc-950/20 data-disabled:opacity-100",
|
20
|
+
data: select_data
|
21
|
+
) %>
|
15
22
|
<% else %>
|
16
|
-
<%= select_tag(
|
23
|
+
<%= select_tag(
|
24
|
+
@name,
|
25
|
+
@options_for_select,
|
26
|
+
multiple: @multiple,
|
27
|
+
class: "relative block w-full appearance-none rounded-lg py-[calc(--spacing(2.5)-1px)] sm:py-[calc(--spacing(1.5)-1px)] pr-[calc(--spacing(10)-1px)] pl-[calc(--spacing(3.5)-1px)] sm:pr-[calc(--spacing(9)-1px)] sm:pl-[calc(--spacing(3)-1px)] [&_optgroup]:font-semibold text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500 data-disabled:border-zinc-950/20 data-disabled:opacity-100",
|
28
|
+
data: select_data
|
29
|
+
) %>
|
17
30
|
<% end %>
|
18
31
|
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"><svg class="size-5 stroke-zinc-500 group-has-data-disabled:stroke-zinc-600 sm:size-4 forced-colors:stroke-[CanvasText]" viewBox="0 0 16 16" aria-hidden="true" fill="none"><path d="M5.75 10.75L8 13L10.25 10.75" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M10.25 5.25L8 3L5.75 5.25" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg></span>
|
19
32
|
</span>
|
33
|
+
<% if has_errors? %>
|
34
|
+
<%= tag.p(
|
35
|
+
error_messages,
|
36
|
+
class: "text-base/6 text-red-600 data-disabled:opacity-50 sm:text-sm/6",
|
37
|
+
data: error_data
|
38
|
+
) %>
|
39
|
+
<% end %>
|
20
40
|
<% end %>
|
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class LightningUiKit::SelectComponent < LightningUiKit::BaseComponent
|
4
|
-
|
4
|
+
include LightningUiKit::Errors
|
5
|
+
|
6
|
+
def initialize(name:, form: nil, label: nil, errors: nil, description: nil, disabled: false, options_for_select: [], multiple: false, **options)
|
5
7
|
@name = name
|
6
8
|
@form = form
|
7
9
|
@label = label
|
10
|
+
@errors = errors
|
8
11
|
@multiple = multiple
|
9
12
|
@description = description
|
10
13
|
@disabled = disabled
|
@@ -22,4 +25,31 @@ class LightningUiKit::SelectComponent < LightningUiKit::BaseComponent
|
|
22
25
|
|
23
26
|
default_data.merge(@options[:data] || {})
|
24
27
|
end
|
28
|
+
|
29
|
+
def select_data
|
30
|
+
{}.tap do |data|
|
31
|
+
if has_errors?
|
32
|
+
data[:invalid] = "true"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def control_data
|
38
|
+
{slot: "control"}.merge(@options[:control_data] || {}).tap do |data|
|
39
|
+
if @disabled
|
40
|
+
data[:disabled] = "true"
|
41
|
+
end
|
42
|
+
if has_errors?
|
43
|
+
data[:invalid] = "true"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def error_data
|
49
|
+
{slot: "error"}.merge(@options[:error_data] || {}).tap do |data|
|
50
|
+
if @disabled
|
51
|
+
data[:disabled] = "true"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
25
55
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div
|
2
2
|
data-slot="field"
|
3
|
-
class="grid grid-cols-[1fr_auto] items-center gap-x-8 gap-y-1 sm:grid-cols-[1fr_auto] *:data-[slot=control]:col-start-2 *:data-[slot=control]:self-center *:data-[slot=label]:col-start-1 *:data-[slot=label]:row-start-1 *:data-[slot=label]:justify-self-start *:data-[slot=description]:col-start-1 *:data-[slot=description]:row-start-2 has-data-[slot=description]:**:data-[slot=label]:font-medium"
|
3
|
+
class="grid grid-cols-[1fr_auto] items-center gap-x-8 gap-y-1 sm:grid-cols-[1fr_auto] *:data-[slot=control]:col-start-2 *:data-[slot=control]:self-center *:data-[slot=label]:col-start-1 *:data-[slot=label]:row-start-1 *:data-[slot=label]:justify-self-start *:data-[slot=description]:col-start-1 *:data-[slot=description]:row-start-2 has-data-[slot=description]:**:data-[slot=label]:font-medium *:data-[slot=error]:col-start-1 *:data-[slot=error]:row-start-3"
|
4
4
|
data-controller="lui-switch"
|
5
5
|
>
|
6
6
|
<% if @label %>
|
@@ -13,8 +13,15 @@
|
|
13
13
|
<%= @description %>
|
14
14
|
</p>
|
15
15
|
<% end %>
|
16
|
+
<% if has_errors? %>
|
17
|
+
<%= tag.p(
|
18
|
+
error_messages,
|
19
|
+
class: "text-base/6 text-red-600 data-disabled:opacity-50 sm:text-sm/6",
|
20
|
+
data: error_data
|
21
|
+
) %>
|
22
|
+
<% end %>
|
16
23
|
<%= tag.button(
|
17
|
-
class: "group relative isolate inline-flex h-6 w-10 cursor-default rounded-full p-[3px] sm:h-5 sm:w-8 transition duration-0 ease-in-out data-changing:duration-200 forced-colors:outline forced-colors:[--switch-bg:Highlight] ] bg-zinc-200 ring-1 ring-black/5 ring-inset data-checked:bg-(--switch-bg) data-checked:ring-(--switch-bg-ring) ) ) focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500
|
24
|
+
class: "group relative isolate inline-flex h-6 w-10 cursor-default rounded-full p-[3px] sm:h-5 sm:w-8 transition duration-0 ease-in-out data-changing:duration-200 forced-colors:outline forced-colors:[--switch-bg:Highlight] ] bg-zinc-200 ring-1 ring-black/5 ring-inset data-checked:bg-(--switch-bg) data-checked:ring-(--switch-bg-ring) ) ) focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500 hover:ring-black/15 hover:data-checked:ring-(--switch-bg-ring) ) data-disabled:bg-zinc-200 data-disabled:opacity-50 data-disabled:data-checked:bg-zinc-200 data-disabled:data-checked:ring-black/5 [--switch-bg-ring:var(--color-zinc-950)]/90 [--switch-bg:var(--color-zinc-900)] ] [--switch-ring:var(--color-zinc-950)]/90 [--switch-shadow:var(--color-black)]/10 [--switch:white]",
|
18
25
|
aria: { checked: @enabled },
|
19
26
|
role: "switch",
|
20
27
|
type: "button",
|
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class LightningUiKit::SwitchComponent < LightningUiKit::BaseComponent
|
4
|
-
|
4
|
+
include LightningUiKit::Errors
|
5
|
+
|
6
|
+
def initialize(name:, form: nil, label: nil, error: nil, description: nil, enabled: false, disabled: false, **options)
|
5
7
|
@name = name
|
6
8
|
@form = form
|
7
9
|
@label = label
|
10
|
+
@error = error
|
8
11
|
@description = description
|
9
12
|
@enabled = enabled
|
10
13
|
@disabled = disabled
|
@@ -28,4 +31,12 @@ class LightningUiKit::SwitchComponent < LightningUiKit::BaseComponent
|
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
34
|
+
|
35
|
+
def error_data
|
36
|
+
{slot: "error"}.merge(@options[:error_data] || {}).tap do |data|
|
37
|
+
if @disabled
|
38
|
+
data[:disabled] = "true"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
31
42
|
end
|
@@ -2,12 +2,12 @@
|
|
2
2
|
class: "[&>[data-slot=label]+[data-slot=control]]:mt-3 [&>[data-slot=label]+[data-slot=description]]:mt-1 [&>[data-slot=description]+[data-slot=control]]:mt-3 [&>[data-slot=control]+[data-slot=description]]:mt-3 [&>[data-slot=control]+[data-slot=error]]:mt-3 *:data-[slot=label]:font-medium",
|
3
3
|
data:
|
4
4
|
) do %>
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
<% if @label %>
|
6
|
+
<%= tag.label(
|
7
|
+
@label,
|
8
|
+
class: "text-base/6 text-zinc-950 select-none data-disabled:opacity-50 sm:text-sm/6",
|
9
|
+
data: label_data
|
10
|
+
) %>
|
11
11
|
<% end %>
|
12
12
|
<% if @description %>
|
13
13
|
<%= tag.p(
|
@@ -17,7 +17,7 @@
|
|
17
17
|
) %>
|
18
18
|
<% end %>
|
19
19
|
<% if @form %>
|
20
|
-
<span data-slot="control" class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm
|
20
|
+
<span data-slot="control" class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500 has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none has-data-invalid:before:shadow-red-500/10">
|
21
21
|
<%= @form.text_area(
|
22
22
|
@name,
|
23
23
|
value: @value,
|
@@ -25,13 +25,13 @@
|
|
25
25
|
cols: @cols,
|
26
26
|
multiple: @multiple,
|
27
27
|
data: input_data,
|
28
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
28
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500 data-disabled:border-zinc-950/20",
|
29
29
|
disabled: @disabled,
|
30
30
|
autofocus: @autofocus
|
31
31
|
) %>
|
32
32
|
</span>
|
33
33
|
<% else %>
|
34
|
-
<span data-slot="control" class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm
|
34
|
+
<span data-slot="control" class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500 has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none has-data-invalid:before:shadow-red-500/10">
|
35
35
|
<%= text_area_tag(
|
36
36
|
@name,
|
37
37
|
@value,
|
@@ -39,10 +39,17 @@
|
|
39
39
|
cols: @cols,
|
40
40
|
multiple: @multiple,
|
41
41
|
data: input_data,
|
42
|
-
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10
|
42
|
+
class: "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 border border-zinc-950/10 hover:border-zinc-950/20 bg-transparent focus:outline-hidden data-invalid:border-red-500 data-invalid:hover:border-red-500 data-disabled:border-zinc-950/20",
|
43
43
|
disabled: @disabled,
|
44
44
|
autofocus: @autofocus
|
45
45
|
) %>
|
46
46
|
</span>
|
47
47
|
<% end %>
|
48
|
+
<% if has_errors? %>
|
49
|
+
<%= tag.p(
|
50
|
+
error_messages,
|
51
|
+
class: "text-base/6 text-red-600 data-disabled:opacity-50 sm:text-sm/6",
|
52
|
+
data: error_data
|
53
|
+
) %>
|
54
|
+
<% end %>
|
48
55
|
<% end %>
|
@@ -1,7 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class LightningUiKit::TextareaComponent < LightningUiKit::BaseComponent
|
4
|
-
|
4
|
+
include LightningUiKit::Errors
|
5
|
+
|
6
|
+
def initialize(name:, value: nil, autofocus: false, label: nil, form: nil, type: :text, error: nil, description: nil, disabled: false, multiple: false, rows: 3, cols: nil, **options)
|
5
7
|
@name = name
|
6
8
|
@value = value
|
7
9
|
@disabled = disabled
|
@@ -9,6 +11,7 @@ class LightningUiKit::TextareaComponent < LightningUiKit::BaseComponent
|
|
9
11
|
@rows = rows
|
10
12
|
@multiple = multiple
|
11
13
|
@cols = cols
|
14
|
+
@error = error
|
12
15
|
@label = label
|
13
16
|
@form = form
|
14
17
|
@type = type
|
@@ -21,7 +24,11 @@ class LightningUiKit::TextareaComponent < LightningUiKit::BaseComponent
|
|
21
24
|
end
|
22
25
|
|
23
26
|
def input_data
|
24
|
-
@options[:input_data] || {}
|
27
|
+
(@options[:input_data] || {}).tap do |data|
|
28
|
+
if has_errors?
|
29
|
+
data[:invalid] = "true"
|
30
|
+
end
|
31
|
+
end
|
25
32
|
end
|
26
33
|
|
27
34
|
def label_data
|
@@ -39,4 +46,12 @@ class LightningUiKit::TextareaComponent < LightningUiKit::BaseComponent
|
|
39
46
|
end
|
40
47
|
end
|
41
48
|
end
|
49
|
+
|
50
|
+
def error_data
|
51
|
+
{slot: "error"}.merge(@options[:error_data] || {}).tap do |data|
|
52
|
+
if @disabled
|
53
|
+
data[:disabled] = "true"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
42
57
|
end
|
@@ -2,9 +2,14 @@ import { Controller } from "@hotwired/stimulus";
|
|
2
2
|
|
3
3
|
export default class extends Controller {
|
4
4
|
static targets = ["content", "item"];
|
5
|
+
static values = {
|
6
|
+
openFirst: { type: Boolean, default: true }
|
7
|
+
};
|
5
8
|
|
6
9
|
connect() {
|
7
|
-
|
10
|
+
if (this.openFirstValue) {
|
11
|
+
this.openItem(this.itemTargets[0]);
|
12
|
+
}
|
8
13
|
}
|
9
14
|
|
10
15
|
toggle(e) {
|
@@ -24,27 +29,27 @@ export default class extends Controller {
|
|
24
29
|
}
|
25
30
|
|
26
31
|
openItem(item) {
|
27
|
-
const content = item.querySelector("[data-accordion-target=content]");
|
32
|
+
const content = item.querySelector("[data-lui-accordion-target=content]");
|
28
33
|
content.classList.remove("grid-rows-[0fr]");
|
29
34
|
content.classList.add("grid-rows-[1fr]");
|
30
35
|
content.classList.remove("opacity-0");
|
31
36
|
content.classList.add("opacity-100");
|
32
|
-
const arrow = item.querySelector("[data-accordion-target=arrow]");
|
37
|
+
const arrow = item.querySelector("[data-lui-accordion-target=arrow]");
|
33
38
|
arrow.classList.add("rotate-180");
|
34
39
|
}
|
35
40
|
|
36
41
|
closeItem(item) {
|
37
|
-
const content = item.querySelector("[data-accordion-target=content]");
|
42
|
+
const content = item.querySelector("[data-lui-accordion-target=content]");
|
38
43
|
content.classList.remove("grid-rows-[1fr]");
|
39
44
|
content.classList.add("grid-rows-[0fr]");
|
40
45
|
content.classList.remove("opacity-100");
|
41
46
|
content.classList.add("opacity-0");
|
42
|
-
const arrow = item.querySelector("[data-accordion-target=arrow]");
|
47
|
+
const arrow = item.querySelector("[data-lui-accordion-target=arrow]");
|
43
48
|
arrow.classList.remove("rotate-180");
|
44
49
|
}
|
45
50
|
|
46
51
|
isOpen(item) {
|
47
|
-
const content = item.querySelector("[data-accordion-target=content]");
|
52
|
+
const content = item.querySelector("[data-lui-accordion-target=content]");
|
48
53
|
return content.classList.contains("grid-rows-[1fr]");
|
49
54
|
}
|
50
55
|
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
import { DirectUpload } from "@rails/activestorage"
|
3
|
+
|
4
|
+
class Upload {
|
5
|
+
constructor(file, controller) {
|
6
|
+
this.controller = controller
|
7
|
+
this.file = file;
|
8
|
+
this.directUpload = new DirectUpload(file, this.controller.inputTarget.dataset.directUploadUrl, this);
|
9
|
+
}
|
10
|
+
|
11
|
+
process() {
|
12
|
+
this.insertUpload();
|
13
|
+
|
14
|
+
this.directUpload.create((error, blob) => {
|
15
|
+
if (error) {
|
16
|
+
const fileContainer = this.controller.filesTarget.querySelector(`#upload_${this.directUpload.id}`)
|
17
|
+
const status = fileContainer.querySelector("[data-lui-dropzone-target='status']")
|
18
|
+
status.textContent = "Failed. " + error
|
19
|
+
status.classList.add("text-red-500")
|
20
|
+
} else {
|
21
|
+
const hiddenField = document.createElement('input')
|
22
|
+
hiddenField.setAttribute("type", "hidden");
|
23
|
+
hiddenField.setAttribute("value", blob.signed_id);
|
24
|
+
hiddenField.name = this.controller.inputTarget.name;
|
25
|
+
this.controller.filesTarget
|
26
|
+
.querySelector(`#upload_${this.directUpload.id}`)
|
27
|
+
.appendChild(hiddenField);
|
28
|
+
this.controller.inputTarget.value = "";
|
29
|
+
}
|
30
|
+
});
|
31
|
+
}
|
32
|
+
|
33
|
+
insertUpload() {
|
34
|
+
const template = this.controller.templateTarget.content.cloneNode(true)
|
35
|
+
template.querySelector('#\\#NEW_FILE').id = `upload_${this.directUpload.id}`
|
36
|
+
template.querySelector("[data-lui-dropzone-target='filename']").textContent = this.file.name
|
37
|
+
template.querySelector("[data-lui-dropzone-target='status']").textContent = "Uploading..."
|
38
|
+
|
39
|
+
this.controller.filesTarget.appendChild(template)
|
40
|
+
}
|
41
|
+
|
42
|
+
directUploadWillStoreFileWithXHR(request) {
|
43
|
+
request.upload.addEventListener("progress", (event) => this.updateProgress(event));
|
44
|
+
}
|
45
|
+
|
46
|
+
updateProgress(event) {
|
47
|
+
const progress = ((event.loaded / event.total) * 100).toFixed(0)
|
48
|
+
const status = progress == 100 ? "Uploaded" : "Uploading..."
|
49
|
+
|
50
|
+
const fileContainer = this.controller.filesTarget.querySelector(`#upload_${this.directUpload.id}`)
|
51
|
+
fileContainer.querySelector("[data-lui-dropzone-target='status']").textContent = status
|
52
|
+
fileContainer.querySelector("[data-lui-dropzone-target='progressbar']").style.width = `${progress}%`
|
53
|
+
fileContainer.querySelector("[data-lui-dropzone-target='percentage-progress']").textContent = `${progress}%`
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
export default class extends Controller {
|
58
|
+
static targets = ["input", "template", "files"]
|
59
|
+
|
60
|
+
selectFiles(_event) {
|
61
|
+
this.inputTarget.click()
|
62
|
+
}
|
63
|
+
|
64
|
+
uploadFiles(event) {
|
65
|
+
event.preventDefault();
|
66
|
+
const files = event.dataTransfer ? event.dataTransfer.files : event.target.files;
|
67
|
+
[...files].forEach(f => new Upload(f, this).process())
|
68
|
+
}
|
69
|
+
|
70
|
+
activate(event) {
|
71
|
+
event.preventDefault()
|
72
|
+
}
|
73
|
+
|
74
|
+
removeFile(event) {
|
75
|
+
event.preventDefault()
|
76
|
+
const container = event.target.closest("[data-lui-dropzone-target='file']")
|
77
|
+
container.remove()
|
78
|
+
}
|
79
|
+
}
|
@@ -2,6 +2,9 @@ const namespace = 'lui'
|
|
2
2
|
|
3
3
|
import { Application } from "@hotwired/stimulus"
|
4
4
|
|
5
|
+
import * as ActiveStorage from "@rails/activestorage"
|
6
|
+
ActiveStorage.start()
|
7
|
+
|
5
8
|
const application = Application.start()
|
6
9
|
window.Stimulus = application
|
7
10
|
|
@@ -14,6 +17,7 @@ import ModalController from './controllers/modal_controller'
|
|
14
17
|
import RevealController from './controllers/reveal_controller'
|
15
18
|
import SwitchController from './controllers/switch_controller'
|
16
19
|
import DropdownController from './controllers/dropdown_controller'
|
20
|
+
import DropzoneController from './controllers/dropzone_controller'
|
17
21
|
|
18
22
|
export function registerLuiControllers(application) {
|
19
23
|
application.register(`${namespace}-clipboard`, ClipboardController)
|
@@ -25,6 +29,7 @@ export function registerLuiControllers(application) {
|
|
25
29
|
application.register(`${namespace}-reveal`, RevealController)
|
26
30
|
application.register(`${namespace}-switch`, SwitchController)
|
27
31
|
application.register(`${namespace}-dropdown`, DropdownController)
|
32
|
+
application.register(`${namespace}-dropzone`, DropzoneController)
|
28
33
|
}
|
29
34
|
registerLuiControllers(application)
|
30
35
|
|