openproject-primer_view_components 0.45.0 → 0.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/app/assets/javascripts/app/components/primer/open_project/sub_header_element.d.ts +5 -1
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +1 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/open_project/sub_header.css +1 -1
- data/app/components/primer/open_project/sub_header.css.json +3 -1
- data/app/components/primer/open_project/sub_header.css.map +1 -1
- data/app/components/primer/open_project/sub_header.pcss +12 -0
- data/app/components/primer/open_project/sub_header.rb +19 -2
- data/app/components/primer/open_project/sub_header_element.d.ts +5 -1
- data/app/components/primer/open_project/sub_header_element.js +32 -0
- data/app/components/primer/open_project/sub_header_element.ts +39 -1
- data/lib/primer/view_components/version.rb +1 -1
- data/previews/primer/open_project/sub_header_preview.rb +15 -2
- data/static/classes.json +3 -0
- metadata +2 -2
@@ -1 +1 @@
|
|
1
|
-
.SubHeader{align-items:center;display:grid;grid-template-areas:"left middle right" "bottom bottom bottom";grid-template-columns:auto 1fr auto;margin-bottom:16px}.SubHeader--expandedSearch{grid-template-areas:"left left left" "bottom bottom bottom"}.SubHeader-rightPane{align-items:center;column-gap:12px;display:flex;grid-area:right}.SubHeader-middlePane{grid-area:middle;text-align:center}.SubHeader-bottomPane{grid-area:bottom}.SubHeader-leftPane{align-items:center;display:flex;gap:12px;grid-area:left;width:100%}.SubHeader-filterContainer{display:flex;gap:8px;width:100%}
|
1
|
+
.SubHeader{align-items:center;display:grid;grid-template-areas:"left middle right" "bottom bottom bottom";grid-template-columns:auto 1fr auto;margin-bottom:16px}.SubHeader--expandedSearch{grid-template-areas:"left left left" "bottom bottom bottom"}.SubHeader-rightPane{align-items:center;column-gap:12px;display:flex;grid-area:right}.SubHeader-middlePane{grid-area:middle;text-align:center}.SubHeader-bottomPane{grid-area:bottom}.SubHeader-leftPane{align-items:center;display:flex;gap:12px;grid-area:left;width:100%}:is(.SubHeader-leftPane [class*=FormControl-input-width--]):not(.FormControl-input-width--auto){width:100vw}.SubHeader-filterContainer{display:flex;gap:8px;width:100%}.SubHeader-filterInput_hiddenClearButton+button.FormControl-input-trailingAction{display:none}
|
@@ -7,6 +7,8 @@
|
|
7
7
|
".SubHeader-middlePane",
|
8
8
|
".SubHeader-bottomPane",
|
9
9
|
".SubHeader-leftPane",
|
10
|
-
".SubHeader-
|
10
|
+
":is(.SubHeader-leftPane [class*=FormControl-input-width--]):not(.FormControl-input-width--auto)",
|
11
|
+
".SubHeader-filterContainer",
|
12
|
+
".SubHeader-filterInput_hiddenClearButton+button.FormControl-input-trailingAction"
|
11
13
|
]
|
12
14
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["sub_header.pcss"],"names":[],"mappings":"AAEA,WAII,kBAAmB,CAHnB,YAAa,CACb,8DAA+D,CAC/D,mCAAoC,CAEpC,kBACJ,CAEA,2BACI,2DACJ,CAEA,qBAGI,kBAAmB,CACnB,eAAgB,CAFhB,YAAa,CADb,eAIJ,CAEA,sBACI,gBAAiB,CACjB,iBACJ,CAEA,sBACI,gBACJ,CAEA,oBAGI,kBAAmB,CADnB,YAAa,CAGb,QAAS,CAJT,cAAe,CAGf,
|
1
|
+
{"version":3,"sources":["sub_header.pcss"],"names":[],"mappings":"AAEA,WAII,kBAAmB,CAHnB,YAAa,CACb,8DAA+D,CAC/D,mCAAoC,CAEpC,kBACJ,CAEA,2BACI,2DACJ,CAEA,qBAGI,kBAAmB,CACnB,eAAgB,CAFhB,YAAa,CADb,eAIJ,CAEA,sBACI,gBAAiB,CACjB,iBACJ,CAEA,sBACI,gBACJ,CAEA,oBAGI,kBAAmB,CADnB,YAAa,CAGb,QAAS,CAJT,cAAe,CAGf,UAUJ,CAJQ,gGACI,WACJ,CAIR,2BACI,YAAa,CAEb,OAAQ,CADR,UAEJ,CAEA,iFACE,YACF","file":"sub_header.css","sourcesContent":["/* CSS for SubHeader */\n\n.SubHeader {\n display: grid;\n grid-template-areas: \"left middle right\" \"bottom bottom bottom\";\n grid-template-columns: auto 1fr auto;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.SubHeader--expandedSearch {\n grid-template-areas: \"left left left\" \"bottom bottom bottom\";\n}\n\n.SubHeader-rightPane {\n grid-area: right;\n display: flex;\n align-items: center;\n column-gap: 12px;\n}\n\n.SubHeader-middlePane {\n grid-area: middle;\n text-align: center;\n}\n\n.SubHeader-bottomPane {\n grid-area: bottom;\n}\n\n.SubHeader-leftPane {\n grid-area: left;\n display: flex;\n align-items: center;\n width: 100%;\n gap: 12px;\n\n /* Since the container is not full width (due to the grid around it)\n we want it to grow, and then be limited by the max-width of the \"FormControl-input-width--xy\" class */\n & [class*='FormControl-input-width--'] {\n &:not(.FormControl-input-width--auto) {\n width: 100vw;\n }\n }\n}\n\n.SubHeader-filterContainer {\n display: flex;\n width: 100%;\n gap: 8px;\n}\n\n.SubHeader-filterInput_hiddenClearButton + button.FormControl-input-trailingAction {\n display: none;\n}\n"]}
|
@@ -34,6 +34,14 @@
|
|
34
34
|
align-items: center;
|
35
35
|
width: 100%;
|
36
36
|
gap: 12px;
|
37
|
+
|
38
|
+
/* Since the container is not full width (due to the grid around it)
|
39
|
+
we want it to grow, and then be limited by the max-width of the "FormControl-input-width--xy" class */
|
40
|
+
& [class*='FormControl-input-width--'] {
|
41
|
+
&:not(.FormControl-input-width--auto) {
|
42
|
+
width: 100vw;
|
43
|
+
}
|
44
|
+
}
|
37
45
|
}
|
38
46
|
|
39
47
|
.SubHeader-filterContainer {
|
@@ -41,3 +49,7 @@
|
|
41
49
|
width: 100%;
|
42
50
|
gap: 8px;
|
43
51
|
}
|
52
|
+
|
53
|
+
.SubHeader-filterInput_hiddenClearButton + button.FormControl-input-trailingAction {
|
54
|
+
display: none;
|
55
|
+
}
|
@@ -38,19 +38,36 @@ module Primer
|
|
38
38
|
renders_one :filter_input, lambda { |name:, label:, **system_arguments|
|
39
39
|
system_arguments[:classes] = class_names(
|
40
40
|
system_arguments[:classes],
|
41
|
-
"SubHeader-filterInput"
|
41
|
+
"SubHeader-filterInput",
|
42
|
+
"SubHeader-filterInput_hiddenClearButton"
|
42
43
|
)
|
43
44
|
system_arguments[:placeholder] ||= I18n.t("button_filter")
|
44
45
|
system_arguments[:leading_visual] ||= { icon: :search }
|
45
46
|
system_arguments[:visually_hide_label] ||= true
|
47
|
+
system_arguments[:input_width] ||= :medium
|
46
48
|
|
47
49
|
system_arguments[:data] ||= {}
|
48
50
|
system_arguments[:data][:target]= "sub-header.filterInput"
|
49
51
|
|
52
|
+
system_arguments[:show_clear_button] = true if system_arguments[:show_clear_button].nil?
|
53
|
+
|
54
|
+
if system_arguments[:show_clear_button]
|
55
|
+
system_arguments[:data] = merge_data(
|
56
|
+
system_arguments,
|
57
|
+
{
|
58
|
+
data: {
|
59
|
+
action: <<~JS
|
60
|
+
input:sub-header#toggleFilterInputClearButton
|
61
|
+
focus:sub-header#toggleFilterInputClearButton
|
62
|
+
JS
|
63
|
+
}
|
64
|
+
}
|
65
|
+
)
|
66
|
+
end
|
50
67
|
|
51
68
|
@mobile_filter_trigger = Primer::Beta::IconButton.new(icon: system_arguments[:leading_visual][:icon],
|
52
69
|
display: [:inline_flex, :none],
|
53
|
-
aria: {label: label },
|
70
|
+
aria: { label: label },
|
54
71
|
"data-action": "click:sub-header#expandFilterInput",
|
55
72
|
"data-targets": HIDDEN_FILTER_TARGET_SELECTOR)
|
56
73
|
|
@@ -1,9 +1,13 @@
|
|
1
1
|
declare class SubHeaderElement extends HTMLElement {
|
2
|
-
filterInput:
|
2
|
+
filterInput: HTMLInputElement;
|
3
3
|
hiddenItemsOnExpandedFilter: HTMLElement[];
|
4
4
|
shownItemsOnExpandedFilter: HTMLElement[];
|
5
|
+
connectedCallback(): void;
|
6
|
+
setupFilterInputClearButton(): void;
|
7
|
+
toggleFilterInputClearButton(): void;
|
5
8
|
expandFilterInput(): void;
|
6
9
|
collapseFilterInput(): void;
|
10
|
+
private waitForCondition;
|
7
11
|
}
|
8
12
|
declare global {
|
9
13
|
interface Window {
|
@@ -6,6 +6,22 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
6
6
|
};
|
7
7
|
import { controller, target, targets } from '@github/catalyst';
|
8
8
|
let SubHeaderElement = class SubHeaderElement extends HTMLElement {
|
9
|
+
connectedCallback() {
|
10
|
+
this.setupFilterInputClearButton();
|
11
|
+
}
|
12
|
+
setupFilterInputClearButton() {
|
13
|
+
this.waitForCondition(() => Boolean(this.filterInput), () => {
|
14
|
+
this.toggleFilterInputClearButton();
|
15
|
+
});
|
16
|
+
}
|
17
|
+
toggleFilterInputClearButton() {
|
18
|
+
if (this.filterInput.value.length > 0) {
|
19
|
+
this.filterInput.classList.remove('SubHeader-filterInput_hiddenClearButton');
|
20
|
+
}
|
21
|
+
else {
|
22
|
+
this.filterInput.classList.add('SubHeader-filterInput_hiddenClearButton');
|
23
|
+
}
|
24
|
+
}
|
9
25
|
expandFilterInput() {
|
10
26
|
for (const item of this.hiddenItemsOnExpandedFilter) {
|
11
27
|
item.classList.add('d-none');
|
@@ -25,6 +41,22 @@ let SubHeaderElement = class SubHeaderElement extends HTMLElement {
|
|
25
41
|
}
|
26
42
|
this.classList.remove('SubHeader--expandedSearch');
|
27
43
|
}
|
44
|
+
// Waits for condition to return true. If it returns false initially, this function creates a
|
45
|
+
// MutationObserver that calls body() whenever the contents of the component change.
|
46
|
+
waitForCondition(condition, body) {
|
47
|
+
if (condition()) {
|
48
|
+
body();
|
49
|
+
}
|
50
|
+
else {
|
51
|
+
const mutationObserver = new MutationObserver(() => {
|
52
|
+
if (condition()) {
|
53
|
+
body();
|
54
|
+
mutationObserver.disconnect();
|
55
|
+
}
|
56
|
+
});
|
57
|
+
mutationObserver.observe(this, { childList: true, subtree: true });
|
58
|
+
}
|
59
|
+
}
|
28
60
|
};
|
29
61
|
__decorate([
|
30
62
|
target
|
@@ -2,10 +2,31 @@ import {controller, target, targets} from '@github/catalyst'
|
|
2
2
|
|
3
3
|
@controller
|
4
4
|
class SubHeaderElement extends HTMLElement {
|
5
|
-
@target filterInput:
|
5
|
+
@target filterInput: HTMLInputElement
|
6
6
|
@targets hiddenItemsOnExpandedFilter: HTMLElement[]
|
7
7
|
@targets shownItemsOnExpandedFilter: HTMLElement[]
|
8
8
|
|
9
|
+
connectedCallback() {
|
10
|
+
this.setupFilterInputClearButton()
|
11
|
+
}
|
12
|
+
|
13
|
+
setupFilterInputClearButton() {
|
14
|
+
this.waitForCondition(
|
15
|
+
() => Boolean(this.filterInput),
|
16
|
+
() => {
|
17
|
+
this.toggleFilterInputClearButton()
|
18
|
+
},
|
19
|
+
)
|
20
|
+
}
|
21
|
+
|
22
|
+
toggleFilterInputClearButton() {
|
23
|
+
if (this.filterInput.value.length > 0) {
|
24
|
+
this.filterInput.classList.remove('SubHeader-filterInput_hiddenClearButton')
|
25
|
+
} else {
|
26
|
+
this.filterInput.classList.add('SubHeader-filterInput_hiddenClearButton')
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
9
30
|
expandFilterInput() {
|
10
31
|
for (const item of this.hiddenItemsOnExpandedFilter) {
|
11
32
|
item.classList.add('d-none')
|
@@ -31,6 +52,23 @@ class SubHeaderElement extends HTMLElement {
|
|
31
52
|
|
32
53
|
this.classList.remove('SubHeader--expandedSearch')
|
33
54
|
}
|
55
|
+
|
56
|
+
// Waits for condition to return true. If it returns false initially, this function creates a
|
57
|
+
// MutationObserver that calls body() whenever the contents of the component change.
|
58
|
+
private waitForCondition(condition: () => boolean, body: () => void) {
|
59
|
+
if (condition()) {
|
60
|
+
body()
|
61
|
+
} else {
|
62
|
+
const mutationObserver = new MutationObserver(() => {
|
63
|
+
if (condition()) {
|
64
|
+
body()
|
65
|
+
mutationObserver.disconnect()
|
66
|
+
}
|
67
|
+
})
|
68
|
+
|
69
|
+
mutationObserver.observe(this, {childList: true, subtree: true})
|
70
|
+
}
|
71
|
+
}
|
34
72
|
}
|
35
73
|
|
36
74
|
declare global {
|
@@ -11,10 +11,23 @@ module Primer
|
|
11
11
|
# @param show_filter_input toggle
|
12
12
|
# @param show_filter_button toggle
|
13
13
|
# @param show_action_button toggle
|
14
|
+
# @param show_clear_button toggle
|
14
15
|
# @param text text
|
15
|
-
|
16
|
+
# @param value text
|
17
|
+
def playground(
|
18
|
+
show_filter_input: true,
|
19
|
+
show_clear_button: true,
|
20
|
+
show_filter_button: true,
|
21
|
+
show_action_button: true,
|
22
|
+
text: nil,
|
23
|
+
value: nil
|
24
|
+
)
|
16
25
|
render(Primer::OpenProject::SubHeader.new) do |component|
|
17
|
-
component.with_filter_input(
|
26
|
+
component.with_filter_input(
|
27
|
+
name: "filter",
|
28
|
+
label: "Filter",
|
29
|
+
show_clear_button: show_clear_button,
|
30
|
+
value: value) if show_filter_input
|
18
31
|
component.with_filter_button do |button|
|
19
32
|
button.with_trailing_visual_counter(count: "15")
|
20
33
|
"Filter"
|
data/static/classes.json
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openproject-primer_view_components
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.46.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-09-
|
12
|
+
date: 2024-09-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: actionview
|