completion-kit 0.20.4 → 0.21.1
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/javascripts/completion_kit/application.js +72 -0
- data/app/assets/stylesheets/completion_kit/application.css +111 -7
- data/app/helpers/completion_kit/application_helper.rb +42 -0
- data/app/views/completion_kit/metrics/_check_spec.html.erb +5 -5
- data/app/views/completion_kit/metrics/_form.html.erb +22 -25
- data/app/views/completion_kit/shared/_branded_select.html.erb +18 -0
- data/lib/completion_kit/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4fc454c51bfbe7917a7b3f248b055d58b6a147fe7e9325dadc196d9aebf7c762
|
|
4
|
+
data.tar.gz: 5e96ffb9c4d1e98c4917ec7847a6b734e9153142184d0b540585d8f7c8aba3b6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 11ad299c28fdb4dc4be3ee113c99ebf19ec6cb9d422dbc180cb253292adc7373d2d183aef7fd21c5e7293c1acc017f3c0689f34a5ded2e13b17674a86cacb6e6
|
|
7
|
+
data.tar.gz: b995b586a1b2c5422be141b9e94476ea0d32928dc81e8aca4210c54c1b4d8ea6cd0d7729621a0155438a2b7819977e6678e1000c343d9160ec09db7120be47e6
|
|
@@ -296,3 +296,75 @@ document.addEventListener("click", function(e) {
|
|
|
296
296
|
btn.textContent = "Applied ✓";
|
|
297
297
|
field.focus({ preventScroll: true });
|
|
298
298
|
});
|
|
299
|
+
|
|
300
|
+
function ckSelectClose(sel) {
|
|
301
|
+
if (!sel.classList.contains("is-open")) return;
|
|
302
|
+
sel.classList.remove("is-open");
|
|
303
|
+
var menu = sel.querySelector("[data-ck-select-menu]");
|
|
304
|
+
var trigger = sel.querySelector("[data-ck-select-trigger]");
|
|
305
|
+
if (menu) menu.hidden = true;
|
|
306
|
+
if (trigger) trigger.setAttribute("aria-expanded", "false");
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function ckSelectOpen(sel) {
|
|
310
|
+
document.querySelectorAll("[data-ck-select].is-open").forEach(ckSelectClose);
|
|
311
|
+
sel.classList.add("is-open");
|
|
312
|
+
var menu = sel.querySelector("[data-ck-select-menu]");
|
|
313
|
+
var trigger = sel.querySelector("[data-ck-select-trigger]");
|
|
314
|
+
if (menu) menu.hidden = false;
|
|
315
|
+
if (trigger) trigger.setAttribute("aria-expanded", "true");
|
|
316
|
+
var current = menu.querySelector('[aria-selected="true"]') || menu.querySelector('[role="option"]');
|
|
317
|
+
if (current) current.focus();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function ckSelectChoose(sel, option) {
|
|
321
|
+
var input = sel.querySelector("[data-ck-select-value]");
|
|
322
|
+
var label = sel.querySelector("[data-ck-select-label]");
|
|
323
|
+
var text = option.querySelector("[data-ck-select-text]");
|
|
324
|
+
sel.querySelectorAll('[role="option"]').forEach(function(o) {
|
|
325
|
+
o.setAttribute("aria-selected", o === option ? "true" : "false");
|
|
326
|
+
});
|
|
327
|
+
input.value = option.getAttribute("data-value");
|
|
328
|
+
if (text) label.textContent = text.textContent;
|
|
329
|
+
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
330
|
+
ckSelectClose(sel);
|
|
331
|
+
var trigger = sel.querySelector("[data-ck-select-trigger]");
|
|
332
|
+
if (trigger) trigger.focus();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
document.addEventListener("click", function(e) {
|
|
336
|
+
var trigger = e.target.closest("[data-ck-select-trigger]");
|
|
337
|
+
if (trigger) {
|
|
338
|
+
var sel = trigger.closest("[data-ck-select]");
|
|
339
|
+
if (sel.classList.contains("is-open")) { ckSelectClose(sel); } else { ckSelectOpen(sel); }
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
var option = e.target.closest('[data-ck-select] [role="option"]');
|
|
343
|
+
if (option) {
|
|
344
|
+
ckSelectChoose(option.closest("[data-ck-select]"), option);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
document.querySelectorAll("[data-ck-select].is-open").forEach(function(sel) {
|
|
348
|
+
if (!sel.contains(e.target)) ckSelectClose(sel);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
document.addEventListener("keydown", function(e) {
|
|
353
|
+
var sel = e.target.closest("[data-ck-select]");
|
|
354
|
+
if (!sel) return;
|
|
355
|
+
var trigger = sel.querySelector("[data-ck-select-trigger]");
|
|
356
|
+
var options = Array.prototype.slice.call(sel.querySelectorAll('[role="option"]'));
|
|
357
|
+
var open = sel.classList.contains("is-open");
|
|
358
|
+
if (e.target === trigger && !open) {
|
|
359
|
+
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") { e.preventDefault(); ckSelectOpen(sel); }
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (!open) return;
|
|
363
|
+
var idx = options.indexOf(document.activeElement);
|
|
364
|
+
if (e.key === "ArrowDown") { e.preventDefault(); (options[idx + 1] || options[0]).focus(); }
|
|
365
|
+
else if (e.key === "ArrowUp") { e.preventDefault(); (options[idx - 1] || options[options.length - 1]).focus(); }
|
|
366
|
+
else if (e.key === "Home") { e.preventDefault(); options[0].focus(); }
|
|
367
|
+
else if (e.key === "End") { e.preventDefault(); options[options.length - 1].focus(); }
|
|
368
|
+
else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); if (options[idx]) ckSelectChoose(sel, options[idx]); }
|
|
369
|
+
else if (e.key === "Escape") { e.preventDefault(); ckSelectClose(sel); trigger.focus(); }
|
|
370
|
+
});
|
|
@@ -1922,13 +1922,6 @@ label.ck-checkbox input {
|
|
|
1922
1922
|
cursor: pointer;
|
|
1923
1923
|
}
|
|
1924
1924
|
|
|
1925
|
-
.ck-radio-info {
|
|
1926
|
-
width: 16px;
|
|
1927
|
-
height: 16px;
|
|
1928
|
-
color: var(--ck-muted);
|
|
1929
|
-
cursor: help;
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1932
1925
|
.ck-field-row {
|
|
1933
1926
|
display: flex;
|
|
1934
1927
|
gap: 1rem;
|
|
@@ -1981,6 +1974,117 @@ label.ck-checkbox input {
|
|
|
1981
1974
|
color: var(--ck-text);
|
|
1982
1975
|
}
|
|
1983
1976
|
|
|
1977
|
+
.ck-select {
|
|
1978
|
+
position: relative;
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
.ck-select__trigger {
|
|
1982
|
+
width: 100%;
|
|
1983
|
+
display: flex;
|
|
1984
|
+
align-items: center;
|
|
1985
|
+
justify-content: space-between;
|
|
1986
|
+
gap: 0.5rem;
|
|
1987
|
+
padding: 0.65rem 0.85rem;
|
|
1988
|
+
border: 1px solid var(--ck-line-strong);
|
|
1989
|
+
border-radius: var(--ck-radius);
|
|
1990
|
+
background: var(--ck-bg);
|
|
1991
|
+
color: var(--ck-text);
|
|
1992
|
+
font-family: var(--ck-mono);
|
|
1993
|
+
font-size: 0.9rem;
|
|
1994
|
+
text-align: left;
|
|
1995
|
+
cursor: pointer;
|
|
1996
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
.ck-select__label {
|
|
2000
|
+
overflow: hidden;
|
|
2001
|
+
text-overflow: ellipsis;
|
|
2002
|
+
white-space: nowrap;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
.ck-select__trigger:focus-visible,
|
|
2006
|
+
.ck-select.is-open .ck-select__trigger {
|
|
2007
|
+
outline: none;
|
|
2008
|
+
border-color: var(--ck-accent);
|
|
2009
|
+
box-shadow: 0 0 0 3px var(--ck-accent-soft);
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
.ck-select__chevron {
|
|
2013
|
+
display: inline-flex;
|
|
2014
|
+
flex-shrink: 0;
|
|
2015
|
+
color: var(--ck-muted);
|
|
2016
|
+
transition: transform 0.15s;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
.ck-select__chevron svg {
|
|
2020
|
+
width: 1rem;
|
|
2021
|
+
height: 1rem;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
.ck-select.is-open .ck-select__chevron {
|
|
2025
|
+
transform: rotate(180deg);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
.ck-select__menu {
|
|
2029
|
+
position: absolute;
|
|
2030
|
+
z-index: 30;
|
|
2031
|
+
left: 0;
|
|
2032
|
+
right: 0;
|
|
2033
|
+
top: calc(100% + 0.35rem);
|
|
2034
|
+
margin: 0;
|
|
2035
|
+
padding: 0.3rem;
|
|
2036
|
+
list-style: none;
|
|
2037
|
+
background: var(--ck-surface);
|
|
2038
|
+
border: 1px solid var(--ck-line-strong);
|
|
2039
|
+
border-radius: var(--ck-radius-lg);
|
|
2040
|
+
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45);
|
|
2041
|
+
max-height: 18rem;
|
|
2042
|
+
overflow-y: auto;
|
|
2043
|
+
font-family: var(--ck-mono);
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
.ck-select__option {
|
|
2047
|
+
display: flex;
|
|
2048
|
+
align-items: center;
|
|
2049
|
+
gap: 0.5rem;
|
|
2050
|
+
padding: 0.5rem 0.6rem;
|
|
2051
|
+
border-radius: var(--ck-radius);
|
|
2052
|
+
color: var(--ck-text);
|
|
2053
|
+
font-size: 0.9rem;
|
|
2054
|
+
cursor: pointer;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
.ck-select__option:hover,
|
|
2058
|
+
.ck-select__option:focus-visible {
|
|
2059
|
+
outline: none;
|
|
2060
|
+
background: var(--ck-surface-hover);
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
.ck-select__option[aria-selected="true"] {
|
|
2064
|
+
color: var(--ck-accent);
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
.ck-select__tick {
|
|
2068
|
+
display: inline-flex;
|
|
2069
|
+
flex-shrink: 0;
|
|
2070
|
+
width: 1rem;
|
|
2071
|
+
color: var(--ck-accent);
|
|
2072
|
+
opacity: 0;
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
.ck-select__tick svg {
|
|
2076
|
+
width: 1rem;
|
|
2077
|
+
height: 1rem;
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
.ck-select__option[aria-selected="true"] .ck-select__tick {
|
|
2081
|
+
opacity: 1;
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
.ck-select__text {
|
|
2085
|
+
flex: 1;
|
|
2086
|
+
}
|
|
2087
|
+
|
|
1984
2088
|
.ck-section-title {
|
|
1985
2089
|
font-size: 1.05rem;
|
|
1986
2090
|
font-weight: 600;
|
|
@@ -169,6 +169,48 @@ module CompletionKit
|
|
|
169
169
|
end
|
|
170
170
|
end
|
|
171
171
|
|
|
172
|
+
CHECK_KIND_LABELS = {
|
|
173
|
+
"contains" => "Contains a phrase",
|
|
174
|
+
"not_contains" => "Does not contain a phrase",
|
|
175
|
+
"equals" => "Equals exactly",
|
|
176
|
+
"regex" => "Matches a pattern",
|
|
177
|
+
"valid_json" => "Is valid JSON",
|
|
178
|
+
"json_path_equals" => "A JSON field equals a value",
|
|
179
|
+
"length_bounds" => "Length is within a range",
|
|
180
|
+
"no_refusal" => "Is not a refusal"
|
|
181
|
+
}.freeze
|
|
182
|
+
|
|
183
|
+
CHECK_TARGET_LABELS = {
|
|
184
|
+
"response_text" => "The response text",
|
|
185
|
+
"input_data" => "The input row",
|
|
186
|
+
"json_path" => "A value from the response JSON"
|
|
187
|
+
}.freeze
|
|
188
|
+
|
|
189
|
+
CHECK_FIELD_LABELS = {
|
|
190
|
+
"value" => "Text to look for",
|
|
191
|
+
"pattern" => "Pattern",
|
|
192
|
+
"json_path" => "JSON path",
|
|
193
|
+
"expected" => "Expected value",
|
|
194
|
+
"target_path" => "Path into the JSON",
|
|
195
|
+
"min" => "Shortest allowed",
|
|
196
|
+
"max" => "Longest allowed",
|
|
197
|
+
"case_sensitive" => "Case sensitive",
|
|
198
|
+
"multiline" => "Multiline",
|
|
199
|
+
"trim" => "Trim whitespace"
|
|
200
|
+
}.freeze
|
|
201
|
+
|
|
202
|
+
def ck_check_kind_label(kind)
|
|
203
|
+
CHECK_KIND_LABELS.fetch(kind.to_s) { kind.to_s.humanize }
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def ck_check_target_label(target)
|
|
207
|
+
CHECK_TARGET_LABELS.fetch(target.to_s) { target.to_s.humanize }
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def ck_check_field_label(key)
|
|
211
|
+
CHECK_FIELD_LABELS.fetch(key.to_s) { key.to_s.humanize }
|
|
212
|
+
end
|
|
213
|
+
|
|
172
214
|
def ck_result_change_badge(change)
|
|
173
215
|
case change
|
|
174
216
|
when "broke"
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<% config = local_assigns.fetch(:config) %>
|
|
2
2
|
<dl class="ck-check-spec">
|
|
3
3
|
<div class="ck-check-spec__row">
|
|
4
|
-
<dt class="ck-check-spec__term">
|
|
5
|
-
<dd class="ck-check-spec__val"
|
|
4
|
+
<dt class="ck-check-spec__term">Rule</dt>
|
|
5
|
+
<dd class="ck-check-spec__val"><%= ck_check_kind_label(config["check_kind"]) %></dd>
|
|
6
6
|
</div>
|
|
7
7
|
<div class="ck-check-spec__row">
|
|
8
|
-
<dt class="ck-check-spec__term">
|
|
9
|
-
<dd class="ck-check-spec__val"
|
|
8
|
+
<dt class="ck-check-spec__term">Checks</dt>
|
|
9
|
+
<dd class="ck-check-spec__val"><%= ck_check_target_label(config["target"]) %></dd>
|
|
10
10
|
</div>
|
|
11
11
|
<% config.except("check_kind", "target").each do |key, value| %>
|
|
12
12
|
<div class="ck-check-spec__row">
|
|
13
|
-
<dt class="ck-check-spec__term"><%= key
|
|
13
|
+
<dt class="ck-check-spec__term"><%= ck_check_field_label(key) %></dt>
|
|
14
14
|
<dd class="ck-check-spec__val"><code class="ck-check-spec__code"><%= value %></code></dd>
|
|
15
15
|
</div>
|
|
16
16
|
<% end %>
|
|
@@ -79,12 +79,10 @@
|
|
|
79
79
|
<label class="ck-radio">
|
|
80
80
|
<%= form.radio_button :metric_type, "llm_judge", checked: !metric.check? %>
|
|
81
81
|
<span>LLM judge (1-5)</span>
|
|
82
|
-
<%= heroicon_tag "information-circle", variant: :outline, size: 16, class: "ck-radio-info", "aria-hidden": "true", title: "An AI reads each response and rates it 1 to 5 stars against your rubric, with a written reason. Best for subjective quality: tone, helpfulness, accuracy." %>
|
|
83
82
|
</label>
|
|
84
83
|
<label class="ck-radio">
|
|
85
84
|
<%= form.radio_button :metric_type, "check", checked: metric.check? %>
|
|
86
85
|
<span>Deterministic check</span>
|
|
87
|
-
<%= heroicon_tag "information-circle", variant: :outline, size: 16, class: "ck-radio-info", "aria-hidden": "true", title: "A rule that passes or fails instantly with no AI and no cost. Best for exact things: valid JSON, contains a phrase, no refusal." %>
|
|
88
86
|
</label>
|
|
89
87
|
</div>
|
|
90
88
|
<% end %>
|
|
@@ -159,63 +157,62 @@
|
|
|
159
157
|
<% check = metric.check_config || {} %>
|
|
160
158
|
<div class="ck-field ck-field--spacious" data-ck-metric-editor="check" <%= "hidden" unless metric.check? %>>
|
|
161
159
|
<p class="ck-section-title">Check</p>
|
|
162
|
-
<p class="ck-hint">A
|
|
160
|
+
<p class="ck-hint">A pass or fail rule with no AI and no cost. You only fill in the fields the chosen rule needs.</p>
|
|
163
161
|
|
|
164
162
|
<div class="ck-field">
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
163
|
+
<p class="ck-label" id="metric_check_kind_label">Rule</p>
|
|
164
|
+
<%= render "completion_kit/shared/branded_select",
|
|
165
|
+
name: "metric[check_config][check_kind]",
|
|
166
|
+
options: CompletionKit::Checks::Registry.kinds.map { |kind| [kind, ck_check_kind_label(kind)] },
|
|
167
|
+
selected: check["check_kind"] || CompletionKit::Checks::Registry.kinds.first,
|
|
168
|
+
labelledby: "metric_check_kind_label" %>
|
|
171
169
|
</div>
|
|
172
170
|
|
|
173
171
|
<div class="ck-field">
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
172
|
+
<p class="ck-label" id="metric_check_target_label">What to check</p>
|
|
173
|
+
<%= render "completion_kit/shared/branded_select",
|
|
174
|
+
name: "metric[check_config][target]",
|
|
175
|
+
options: CompletionKit::Checks::TargetResolver::TARGETS.map { |target| [target, ck_check_target_label(target)] },
|
|
176
|
+
selected: check["target"] || CompletionKit::Checks::TargetResolver::TARGETS.first,
|
|
177
|
+
labelledby: "metric_check_target_label" %>
|
|
180
178
|
</div>
|
|
181
179
|
|
|
182
180
|
<div class="ck-field" data-ck-check-field="target_path">
|
|
183
|
-
<label class="ck-label" for="metric_check_target_path">
|
|
184
|
-
<p class="ck-hint">
|
|
181
|
+
<label class="ck-label" for="metric_check_target_path">Path into the JSON</label>
|
|
182
|
+
<p class="ck-hint">Where to look inside the response, like data.items.0.name.</p>
|
|
185
183
|
<input type="text" name="metric[check_config][target_path]" id="metric_check_target_path" class="ck-input" value="<%= check["target_path"] %>">
|
|
186
184
|
</div>
|
|
187
185
|
|
|
188
186
|
<div class="ck-field" data-ck-check-field="value">
|
|
189
|
-
<label class="ck-label" for="metric_check_value">
|
|
190
|
-
<p class="ck-hint">The substring or exact string for contains, not_contains, or equals.</p>
|
|
187
|
+
<label class="ck-label" for="metric_check_value">Text to look for</label>
|
|
191
188
|
<input type="text" name="metric[check_config][value]" id="metric_check_value" class="ck-input" value="<%= check["value"] %>">
|
|
192
189
|
</div>
|
|
193
190
|
|
|
194
191
|
<div class="ck-field" data-ck-check-field="pattern">
|
|
195
192
|
<label class="ck-label" for="metric_check_pattern">Pattern</label>
|
|
196
|
-
<p class="ck-hint">A regular expression
|
|
193
|
+
<p class="ck-hint">A regular expression to match against.</p>
|
|
197
194
|
<input type="text" name="metric[check_config][pattern]" id="metric_check_pattern" class="ck-input" value="<%= check["pattern"] %>">
|
|
198
195
|
</div>
|
|
199
196
|
|
|
200
197
|
<div class="ck-field" data-ck-check-field="json_path">
|
|
201
198
|
<label class="ck-label" for="metric_check_json_path">JSON path</label>
|
|
202
|
-
<p class="ck-hint">
|
|
199
|
+
<p class="ck-hint">The path to the value inside the response, like data.status.</p>
|
|
203
200
|
<input type="text" name="metric[check_config][json_path]" id="metric_check_json_path" class="ck-input" value="<%= check["json_path"] %>">
|
|
204
201
|
</div>
|
|
205
202
|
|
|
206
203
|
<div class="ck-field" data-ck-check-field="expected">
|
|
207
|
-
<label class="ck-label" for="metric_check_expected">Expected</label>
|
|
208
|
-
<p class="ck-hint">The value
|
|
204
|
+
<label class="ck-label" for="metric_check_expected">Expected value</label>
|
|
205
|
+
<p class="ck-hint">The value it should equal.</p>
|
|
209
206
|
<input type="text" name="metric[check_config][expected]" id="metric_check_expected" class="ck-input" value="<%= check["expected"] %>">
|
|
210
207
|
</div>
|
|
211
208
|
|
|
212
209
|
<div class="ck-field-row">
|
|
213
210
|
<div class="ck-field" data-ck-check-field="min">
|
|
214
|
-
<label class="ck-label" for="metric_check_min">
|
|
211
|
+
<label class="ck-label" for="metric_check_min">Shortest allowed</label>
|
|
215
212
|
<input type="number" name="metric[check_config][min]" id="metric_check_min" class="ck-input" value="<%= check["min"] %>">
|
|
216
213
|
</div>
|
|
217
214
|
<div class="ck-field" data-ck-check-field="max">
|
|
218
|
-
<label class="ck-label" for="metric_check_max">
|
|
215
|
+
<label class="ck-label" for="metric_check_max">Longest allowed</label>
|
|
219
216
|
<input type="number" name="metric[check_config][max]" id="metric_check_max" class="ck-input" value="<%= check["max"] %>">
|
|
220
217
|
</div>
|
|
221
218
|
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<% chosen = options.find { |value, _label| value.to_s == selected.to_s } || options.first %>
|
|
2
|
+
<div class="ck-select" data-ck-select>
|
|
3
|
+
<input type="hidden" name="<%= name %>" value="<%= chosen && chosen.first %>" data-ck-select-value>
|
|
4
|
+
<button type="button" class="ck-select__trigger" data-ck-select-trigger
|
|
5
|
+
aria-haspopup="listbox" aria-expanded="false" aria-labelledby="<%= labelledby %>">
|
|
6
|
+
<span class="ck-select__label" data-ck-select-label><%= chosen && chosen.last %></span>
|
|
7
|
+
<span class="ck-select__chevron" aria-hidden="true"><%= heroicon_tag "chevron-down" %></span>
|
|
8
|
+
</button>
|
|
9
|
+
<ul class="ck-select__menu" role="listbox" hidden data-ck-select-menu aria-labelledby="<%= labelledby %>">
|
|
10
|
+
<% options.each do |value, label| %>
|
|
11
|
+
<li class="ck-select__option" role="option" tabindex="-1" data-value="<%= value %>"
|
|
12
|
+
aria-selected="<%= chosen && chosen.first.to_s == value.to_s ? "true" : "false" %>">
|
|
13
|
+
<span class="ck-select__tick" aria-hidden="true"><%= heroicon_tag "check" %></span>
|
|
14
|
+
<span class="ck-select__text" data-ck-select-text><%= label %></span>
|
|
15
|
+
</li>
|
|
16
|
+
<% end %>
|
|
17
|
+
</ul>
|
|
18
|
+
</div>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: completion-kit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.21.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Damien Bastin
|
|
@@ -419,6 +419,7 @@ files:
|
|
|
419
419
|
- app/views/completion_kit/runs/index.html.erb
|
|
420
420
|
- app/views/completion_kit/runs/new.html.erb
|
|
421
421
|
- app/views/completion_kit/runs/show.html.erb
|
|
422
|
+
- app/views/completion_kit/shared/_branded_select.html.erb
|
|
422
423
|
- app/views/completion_kit/shared/_settings_nav.html.erb
|
|
423
424
|
- app/views/completion_kit/suggestions/_scoreboard.html.erb
|
|
424
425
|
- app/views/completion_kit/suggestions/_state.html.erb
|