primer_view_components 0.0.94 → 0.0.95
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/CHANGELOG.md +26 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/components/primer/alpha/dialog.rb +3 -3
- data/app/components/primer/alpha/toggle_switch.js +3 -0
- data/app/components/primer/alpha/toggle_switch.ts +3 -0
- data/app/components/primer/alpha/tool_tip.js +17 -2
- data/app/components/primer/alpha/tool_tip.ts +14 -2
- data/app/components/primer/beta/icon_button.html.erb +1 -1
- data/app/components/primer/beta/icon_button.rb +5 -3
- data/app/components/primer/button_component.rb +1 -1
- data/app/components/primer/experimental/action_bar.d.ts +14 -0
- data/app/components/primer/experimental/action_bar.js +141 -0
- data/app/components/primer/icon_button.rb +1 -1
- data/app/lib/primer/fetch_or_fallback_helper.rb +1 -1
- data/lib/primer/deprecations.rb +2 -2
- data/lib/primer/forms/builder.rb +2 -2
- data/lib/primer/forms/check_box.html.erb +5 -1
- data/lib/primer/forms/check_box.rb +11 -0
- data/lib/primer/forms/dsl/check_box_group_input.rb +17 -4
- data/lib/primer/forms/dsl/check_box_input.rb +21 -2
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/tasks/coverage.rake +1 -1
- data/lib/tasks/docs.rake +19 -15
- data/lib/tasks/static.rake +1 -1
- data/lib/tasks/test.rake +54 -0
- data/lib/tasks/utilities.rake +1 -0
- data/static/arguments.json +2042 -0
- data/static/audited_at.json +0 -2
- data/static/constants.json +0 -4
- data/static/statuses.json +2 -4
- metadata +6 -6
- data/app/components/primer/base_button.rb +0 -7
- data/app/components/primer/button_group.rb +0 -7
- data/lib/tasks/deprecated.rake +0 -27
- data/static/arguments.yml +0 -1358
@@ -105,10 +105,10 @@ module Primer
|
|
105
105
|
# <% end %>
|
106
106
|
# @param id [String] The id of the dialog.
|
107
107
|
# @param title [String] Describes the content of the dialog.
|
108
|
-
# @param subtitle [String] Provides
|
108
|
+
# @param subtitle [String] Provides additional context for the dialog, also setting the `aria-describedby` attribute.
|
109
109
|
# @param size [Symbol] The size of the dialog. <%= one_of(Primer::Alpha::Dialog::SIZE_OPTIONS) %>
|
110
|
-
# @param position [Symbol] The
|
111
|
-
# @param position_narrow [Symbol] The
|
110
|
+
# @param position [Symbol] The position of the dialog. <%= one_of(Primer::Alpha::Dialog::POSITION_OPTIONS) %>
|
111
|
+
# @param position_narrow [Symbol] The position of the dialog when narrow. <%= one_of(Primer::Alpha::Dialog::POSITION_NARROW_OPTIONS) %>
|
112
112
|
# @param visually_hide_title [Boolean] If true will hide the heading title, while still making it available to Screen Readers.
|
113
113
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
114
114
|
def initialize(
|
@@ -102,6 +102,9 @@ let ToggleSwitchElement = class ToggleSwitchElement extends HTMLElement {
|
|
102
102
|
const response = await fetch(this.src, {
|
103
103
|
credentials: 'same-origin',
|
104
104
|
method: 'POST',
|
105
|
+
headers: {
|
106
|
+
'Requested-With': 'XMLHttpRequest'
|
107
|
+
},
|
105
108
|
body
|
106
109
|
});
|
107
110
|
if (response.ok) {
|
@@ -124,6 +124,9 @@ export class ToggleSwitchElement extends HTMLElement {
|
|
124
124
|
const response = await fetch(this.src, {
|
125
125
|
credentials: 'same-origin',
|
126
126
|
method: 'POST',
|
127
|
+
headers: {
|
128
|
+
'Requested-With': 'XMLHttpRequest'
|
129
|
+
},
|
127
130
|
body
|
128
131
|
})
|
129
132
|
if (response.ok) {
|
@@ -247,7 +247,12 @@ class ToolTipElement extends HTMLElement {
|
|
247
247
|
if (this.type === 'label') {
|
248
248
|
let labelledBy = this.control.getAttribute('aria-labelledby');
|
249
249
|
if (labelledBy) {
|
250
|
-
|
250
|
+
if (!labelledBy.split(' ').includes(this.id)) {
|
251
|
+
labelledBy = `${labelledBy} ${this.id}`;
|
252
|
+
}
|
253
|
+
else {
|
254
|
+
labelledBy = `${labelledBy}`;
|
255
|
+
}
|
251
256
|
}
|
252
257
|
else {
|
253
258
|
labelledBy = this.id;
|
@@ -258,7 +263,17 @@ class ToolTipElement extends HTMLElement {
|
|
258
263
|
}
|
259
264
|
else {
|
260
265
|
let describedBy = this.control.getAttribute('aria-describedby');
|
261
|
-
|
266
|
+
if (describedBy) {
|
267
|
+
if (!describedBy.split(' ').includes(this.id)) {
|
268
|
+
describedBy = `${describedBy} ${this.id}`;
|
269
|
+
}
|
270
|
+
else {
|
271
|
+
describedBy = `${describedBy}`;
|
272
|
+
}
|
273
|
+
}
|
274
|
+
else {
|
275
|
+
describedBy = this.id;
|
276
|
+
}
|
262
277
|
this.control.setAttribute('aria-describedby', describedBy);
|
263
278
|
}
|
264
279
|
}
|
@@ -264,7 +264,11 @@ class ToolTipElement extends HTMLElement {
|
|
264
264
|
if (this.type === 'label') {
|
265
265
|
let labelledBy = this.control.getAttribute('aria-labelledby')
|
266
266
|
if (labelledBy) {
|
267
|
-
|
267
|
+
if (!labelledBy.split(' ').includes(this.id)) {
|
268
|
+
labelledBy = `${labelledBy} ${this.id}`
|
269
|
+
} else {
|
270
|
+
labelledBy = `${labelledBy}`
|
271
|
+
}
|
268
272
|
} else {
|
269
273
|
labelledBy = this.id
|
270
274
|
}
|
@@ -274,7 +278,15 @@ class ToolTipElement extends HTMLElement {
|
|
274
278
|
this.setAttribute('aria-hidden', 'true')
|
275
279
|
} else {
|
276
280
|
let describedBy = this.control.getAttribute('aria-describedby')
|
277
|
-
|
281
|
+
if (describedBy) {
|
282
|
+
if (!describedBy.split(' ').includes(this.id)) {
|
283
|
+
describedBy = `${describedBy} ${this.id}`
|
284
|
+
} else {
|
285
|
+
describedBy = `${describedBy}`
|
286
|
+
}
|
287
|
+
} else {
|
288
|
+
describedBy = this.id
|
289
|
+
}
|
278
290
|
this.control.setAttribute('aria-describedby', describedBy)
|
279
291
|
}
|
280
292
|
} else if (name === 'data-direction') {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%= render Primer::ConditionalWrapper.new(condition: render_tooltip?, tag: :div, classes: "Button-withTooltip") do %>
|
1
|
+
<%= render Primer::ConditionalWrapper.new(condition: render_tooltip?, tag: :div, classes: "Button-withTooltip", **@wrapper_arguments) do %>
|
2
2
|
<%= render Primer::Beta::BaseButton.new(**@system_arguments) do -%>
|
3
3
|
<%= render Primer::OcticonComponent.new(icon: @icon, classes: "Button-visual") %>
|
4
4
|
<% end -%>
|
@@ -47,17 +47,19 @@ module Primer
|
|
47
47
|
# <%= render(Primer::Beta::IconButton.new(icon: :search, "aria-label": "Search", tooltip_direction: :e)) %>
|
48
48
|
#
|
49
49
|
# @param icon [String] Name of <%= link_to_octicons %> to use.
|
50
|
+
# @param wrapper_arguments [Hash] Optional keyword arguments to be passed to the wrapper `<div>` tag.
|
50
51
|
# @param scheme [Symbol] <%= one_of(Primer::Beta::IconButton::SCHEME_OPTIONS) %>
|
51
52
|
# @param size [Symbol] <%= one_of(Primer::Beta::Button::SIZE_OPTIONS) %>
|
52
|
-
# @param tag [Symbol] <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
|
53
|
-
# @param type [Symbol] <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
|
53
|
+
# @param tag [Symbol] <%= one_of(Primer::Beta::BaseButton::TAG_OPTIONS) %>
|
54
|
+
# @param type [Symbol] <%= one_of(Primer::Beta::BaseButton::TYPE_OPTIONS) %>
|
54
55
|
# @param aria-label [String] String that can be read by assistive technology. A label should be short and concise. See the accessibility section for more information.
|
55
56
|
# @param aria-description [String] String that can be read by assistive technology. A description can be longer as it is intended to provide more context and information. See the accessibility section for more information.
|
56
57
|
# @param tooltip_direction [Symbol] (Primer::Alpha::Tooltip::DIRECTION_DEFAULT) <%= one_of(Primer::Alpha::Tooltip::DIRECTION_OPTIONS) %>
|
57
58
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
58
|
-
def initialize(icon:, scheme: DEFAULT_SCHEME, tooltip_direction: Primer::Alpha::Tooltip::DIRECTION_DEFAULT, size: Primer::Beta::Button::DEFAULT_SIZE, **system_arguments)
|
59
|
+
def initialize(icon:, scheme: DEFAULT_SCHEME, wrapper_arguments: {}, tooltip_direction: Primer::Alpha::Tooltip::DIRECTION_DEFAULT, size: Primer::Beta::Button::DEFAULT_SIZE, **system_arguments)
|
59
60
|
@icon = icon
|
60
61
|
|
62
|
+
@wrapper_arguments = wrapper_arguments
|
61
63
|
@system_arguments = system_arguments
|
62
64
|
@system_arguments[:id] ||= "icon-button-#{SecureRandom.hex(4)}"
|
63
65
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
export declare class ActionBarElement extends HTMLElement {
|
2
|
+
#private;
|
3
|
+
items: HTMLElement[];
|
4
|
+
menuItems: HTMLElement[];
|
5
|
+
itemContainer: HTMLElement;
|
6
|
+
moreMenu: HTMLElement;
|
7
|
+
connectedCallback(): void;
|
8
|
+
disconnectedCallback(): void;
|
9
|
+
}
|
10
|
+
declare global {
|
11
|
+
interface Window {
|
12
|
+
ActionBarElement: typeof ActionBarElement;
|
13
|
+
}
|
14
|
+
}
|
@@ -0,0 +1,141 @@
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
8
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
11
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
12
|
+
};
|
13
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
14
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
15
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
16
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
17
|
+
};
|
18
|
+
var _ActionBarElement_instances, _ActionBarElement_observer, _ActionBarElement_initialBarWidth, _ActionBarElement_previousBarWidth, _ActionBarElement_itemGap, _ActionBarElement_focusController, _ActionBarElement_focusSettings, _ActionBarElement_availableSpace, _ActionBarElement_shrinking, _ActionBarElement_growing;
|
19
|
+
import { controller, targets, target } from '@github/catalyst';
|
20
|
+
import { focusZone, FocusKeys } from '@primer/behaviors';
|
21
|
+
let ActionBarElement = class ActionBarElement extends HTMLElement {
|
22
|
+
constructor() {
|
23
|
+
super(...arguments);
|
24
|
+
_ActionBarElement_instances.add(this);
|
25
|
+
_ActionBarElement_observer.set(this, void 0);
|
26
|
+
_ActionBarElement_initialBarWidth.set(this, void 0);
|
27
|
+
_ActionBarElement_previousBarWidth.set(this, void 0);
|
28
|
+
_ActionBarElement_itemGap.set(this, void 0);
|
29
|
+
_ActionBarElement_focusController.set(this, void 0);
|
30
|
+
_ActionBarElement_focusSettings.set(this, {
|
31
|
+
bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd
|
32
|
+
});
|
33
|
+
}
|
34
|
+
connectedCallback() {
|
35
|
+
var _a, _b, _c;
|
36
|
+
__classPrivateFieldSet(this, _ActionBarElement_initialBarWidth, this.offsetWidth, "f");
|
37
|
+
__classPrivateFieldSet(this, _ActionBarElement_previousBarWidth, this.offsetWidth, "f");
|
38
|
+
__classPrivateFieldSet(this, _ActionBarElement_itemGap, parseInt((_a = window.getComputedStyle(this.itemContainer)) === null || _a === void 0 ? void 0 : _a.columnGap, 10) || 0, "f");
|
39
|
+
// Calculate the width of all the items before hiding anything
|
40
|
+
for (const item of this.items) {
|
41
|
+
const width = item.getBoundingClientRect().width;
|
42
|
+
const marginLeft = parseInt((_b = window.getComputedStyle(item)) === null || _b === void 0 ? void 0 : _b.marginLeft, 10);
|
43
|
+
const marginRight = parseInt((_c = window.getComputedStyle(item)) === null || _c === void 0 ? void 0 : _c.marginRight, 10);
|
44
|
+
item.setAttribute('data-offset-width', `${width + marginLeft + marginRight}`);
|
45
|
+
}
|
46
|
+
__classPrivateFieldSet(this, _ActionBarElement_focusController, focusZone(this, __classPrivateFieldGet(this, _ActionBarElement_focusSettings, "f")), "f");
|
47
|
+
this.style.maxWidth = `${this.itemContainer.offsetWidth}px`;
|
48
|
+
// Calculate visible items on page load until there is enough space
|
49
|
+
// to show all items or the first item is hidden
|
50
|
+
while (__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_availableSpace).call(this) < this.moreMenu.offsetWidth + __classPrivateFieldGet(this, _ActionBarElement_itemGap, "f") * 0.5 && !this.items[0].hidden) {
|
51
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_shrinking).call(this);
|
52
|
+
}
|
53
|
+
this.style.overflow = 'visible';
|
54
|
+
__classPrivateFieldSet(this, _ActionBarElement_observer, new ResizeObserver(entries => {
|
55
|
+
for (const entry of entries) {
|
56
|
+
// Only recalculate if the bar width changed
|
57
|
+
if (__classPrivateFieldGet(this, _ActionBarElement_initialBarWidth, "f") !== entry.contentRect.width) {
|
58
|
+
if (entry.contentRect.width < __classPrivateFieldGet(this, _ActionBarElement_previousBarWidth, "f")) {
|
59
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_shrinking).call(this);
|
60
|
+
}
|
61
|
+
else {
|
62
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_growing).call(this);
|
63
|
+
}
|
64
|
+
__classPrivateFieldSet(this, _ActionBarElement_previousBarWidth, entry.contentRect.width, "f");
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}), "f");
|
68
|
+
__classPrivateFieldGet(this, _ActionBarElement_observer, "f").observe(this);
|
69
|
+
}
|
70
|
+
disconnectedCallback() {
|
71
|
+
var _a;
|
72
|
+
(_a = __classPrivateFieldGet(this, _ActionBarElement_focusController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
73
|
+
__classPrivateFieldGet(this, _ActionBarElement_observer, "f").unobserve(this);
|
74
|
+
}
|
75
|
+
};
|
76
|
+
_ActionBarElement_observer = new WeakMap(), _ActionBarElement_initialBarWidth = new WeakMap(), _ActionBarElement_previousBarWidth = new WeakMap(), _ActionBarElement_itemGap = new WeakMap(), _ActionBarElement_focusController = new WeakMap(), _ActionBarElement_focusSettings = new WeakMap(), _ActionBarElement_instances = new WeakSet(), _ActionBarElement_availableSpace = function _ActionBarElement_availableSpace() {
|
77
|
+
// Get the offset of the item container from the container edge
|
78
|
+
return this.offsetWidth - this.itemContainer.offsetWidth;
|
79
|
+
}, _ActionBarElement_shrinking = function _ActionBarElement_shrinking() {
|
80
|
+
var _a;
|
81
|
+
if (this.items[0].hidden) {
|
82
|
+
return;
|
83
|
+
}
|
84
|
+
const gapSpace = __classPrivateFieldGet(this, _ActionBarElement_itemGap, "f") * 0.5;
|
85
|
+
if (__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_availableSpace).call(this) < this.moreMenu.offsetWidth + gapSpace) {
|
86
|
+
const visibleItems = this.items.filter(item => !item.hidden);
|
87
|
+
const hiddenMenuItems = this.menuItems.filter(item => item.hidden);
|
88
|
+
visibleItems[visibleItems.length - 1].hidden = true;
|
89
|
+
hiddenMenuItems[hiddenMenuItems.length - 1].hidden = false;
|
90
|
+
if (this.moreMenu.hidden) {
|
91
|
+
this.moreMenu.hidden = false;
|
92
|
+
}
|
93
|
+
// Reset focus controller
|
94
|
+
(_a = __classPrivateFieldGet(this, _ActionBarElement_focusController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
95
|
+
__classPrivateFieldSet(this, _ActionBarElement_focusController, focusZone(this, __classPrivateFieldGet(this, _ActionBarElement_focusSettings, "f")), "f");
|
96
|
+
}
|
97
|
+
}, _ActionBarElement_growing = function _ActionBarElement_growing() {
|
98
|
+
var _a;
|
99
|
+
if (this.moreMenu.hidden) {
|
100
|
+
return;
|
101
|
+
}
|
102
|
+
const gapSpace = __classPrivateFieldGet(this, _ActionBarElement_itemGap, "f") * 0.5;
|
103
|
+
const hiddenItems = this.items.filter(item => item.hidden);
|
104
|
+
if (hiddenItems.length === 0) {
|
105
|
+
return;
|
106
|
+
}
|
107
|
+
const hiddenItemWidth = Number(hiddenItems[0].getAttribute('data-offset-width'));
|
108
|
+
if (__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_availableSpace).call(this) >= this.moreMenu.offsetWidth + hiddenItemWidth + gapSpace) {
|
109
|
+
const visibleMenuItems = this.menuItems.filter(item => !item.hidden);
|
110
|
+
hiddenItems[0].hidden = false;
|
111
|
+
visibleMenuItems[0].hidden = true;
|
112
|
+
if (hiddenItems.length === 2) {
|
113
|
+
hiddenItems[1].hidden = false;
|
114
|
+
visibleMenuItems[1].hidden = true;
|
115
|
+
}
|
116
|
+
// If there was only one item left, hide the more menu
|
117
|
+
if (hiddenItems.length <= 2) {
|
118
|
+
this.moreMenu.hidden = true;
|
119
|
+
}
|
120
|
+
// Reset focus controller
|
121
|
+
(_a = __classPrivateFieldGet(this, _ActionBarElement_focusController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
122
|
+
__classPrivateFieldSet(this, _ActionBarElement_focusController, focusZone(this, __classPrivateFieldGet(this, _ActionBarElement_focusSettings, "f")), "f");
|
123
|
+
}
|
124
|
+
};
|
125
|
+
__decorate([
|
126
|
+
targets
|
127
|
+
], ActionBarElement.prototype, "items", void 0);
|
128
|
+
__decorate([
|
129
|
+
targets
|
130
|
+
], ActionBarElement.prototype, "menuItems", void 0);
|
131
|
+
__decorate([
|
132
|
+
target
|
133
|
+
], ActionBarElement.prototype, "itemContainer", void 0);
|
134
|
+
__decorate([
|
135
|
+
target
|
136
|
+
], ActionBarElement.prototype, "moreMenu", void 0);
|
137
|
+
ActionBarElement = __decorate([
|
138
|
+
controller
|
139
|
+
], ActionBarElement);
|
140
|
+
export { ActionBarElement };
|
141
|
+
window.ActionBarElement = ActionBarElement;
|
@@ -12,7 +12,7 @@ module Primer
|
|
12
12
|
# Either `aria-label` or `aria-description` will be used for the `Tooltip` text, depending on which one is present.
|
13
13
|
# [Learn more about best functional image practices (WAI Images)](https://www.w3.org/WAI/tutorials/images/functional)
|
14
14
|
class IconButton < Primer::Component
|
15
|
-
status :
|
15
|
+
status :deprecated
|
16
16
|
|
17
17
|
DEFAULT_SCHEME = :default
|
18
18
|
SCHEME_MAPPINGS = {
|
@@ -33,7 +33,7 @@ module Primer
|
|
33
33
|
|
34
34
|
given_value
|
35
35
|
else
|
36
|
-
if fallback_raises && ENV["RAILS_ENV"] != "production"
|
36
|
+
if fallback_raises && ENV["RAILS_ENV"] != "production"
|
37
37
|
raise InvalidValueError, <<~MSG
|
38
38
|
fetch_or_fallback was called with an invalid value.
|
39
39
|
|
data/lib/primer/deprecations.rb
CHANGED
@@ -7,10 +7,9 @@ module Primer
|
|
7
7
|
DEPRECATED_COMPONENTS = {
|
8
8
|
"Primer::Alpha::AutoComplete" => "Primer::Beta::AutoComplete",
|
9
9
|
"Primer::Alpha::AutoComplete::Item" => "Primer::Beta::AutoComplete::Item",
|
10
|
-
"Primer::BaseButton" => "Primer::Beta::BaseButton",
|
11
10
|
"Primer::BlankslateComponent" => "Primer::Beta::Blankslate",
|
12
11
|
"Primer::BoxComponent" => "Primer::Box",
|
13
|
-
"Primer::
|
12
|
+
"Primer::ButtonComponent" => "Primer::Beta::Button",
|
14
13
|
"Primer::CloseButton" => "Primer::Beta::CloseButton",
|
15
14
|
"Primer::CounterComponent" => "Primer::Beta::Counter",
|
16
15
|
"Primer::DetailsComponent" => "Primer::Beta::Details",
|
@@ -19,6 +18,7 @@ module Primer
|
|
19
18
|
"Primer::FlexItemComponent" => nil,
|
20
19
|
"Primer::HeadingComponent" => "Primer::Beta::Heading",
|
21
20
|
"Primer::HiddenTextExpander" => "Primer::Alpha::HiddenTextExpander",
|
21
|
+
"Primer::IconButton" => "Primer::Beta::IconButton",
|
22
22
|
"Primer::Tooltip" => "Primer::Alpha::Tooltip"
|
23
23
|
}.freeze
|
24
24
|
|
data/lib/primer/forms/builder.rb
CHANGED
@@ -14,8 +14,8 @@ module Primer
|
|
14
14
|
super(*args, classify(options), &block)
|
15
15
|
end
|
16
16
|
|
17
|
-
def check_box(
|
18
|
-
super(
|
17
|
+
def check_box(method, options = {}, checked_value = 1, unchecked_value = 0, &block)
|
18
|
+
super(method, classify(options), checked_value, unchecked_value, &block)
|
19
19
|
end
|
20
20
|
|
21
21
|
def radio_button(*args, **options, &block)
|
@@ -1,5 +1,9 @@
|
|
1
1
|
<div class="FormControl-checkbox-wrap">
|
2
|
-
|
2
|
+
<% if @input.scheme == :array %>
|
3
|
+
<%= builder.check_box(@input.name, @input.input_arguments, checked_value, nil) %>
|
4
|
+
<% else %>
|
5
|
+
<%= builder.check_box(@input.name, @input.input_arguments) %>
|
6
|
+
<% end %>
|
3
7
|
<span class="FormControl-checkbox-labelWrap">
|
4
8
|
<%= builder.label(@input.name, **@input.label_arguments) do %>
|
5
9
|
<%= @input.label %>
|
@@ -10,6 +10,17 @@ module Primer
|
|
10
10
|
@input = input
|
11
11
|
@input.add_label_classes("FormControl-label")
|
12
12
|
@input.add_input_classes("FormControl-checkbox")
|
13
|
+
|
14
|
+
return unless @input.scheme == :array
|
15
|
+
|
16
|
+
@input.input_arguments[:multiple] = true
|
17
|
+
@input.label_arguments[:value] = checked_value
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def checked_value
|
23
|
+
@input.value || "1"
|
13
24
|
end
|
14
25
|
end
|
15
26
|
end
|
@@ -7,7 +7,8 @@ module Primer
|
|
7
7
|
class CheckBoxGroupInput < Input
|
8
8
|
attr_reader :label, :check_boxes
|
9
9
|
|
10
|
-
def initialize(label: nil, **system_arguments)
|
10
|
+
def initialize(name: nil, label: nil, **system_arguments)
|
11
|
+
@name = name
|
11
12
|
@label = label
|
12
13
|
@check_boxes = []
|
13
14
|
|
@@ -31,9 +32,21 @@ module Primer
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def check_box(**system_arguments)
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
args = {
|
36
|
+
name: @name,
|
37
|
+
**system_arguments,
|
38
|
+
builder: @builder,
|
39
|
+
form: @form,
|
40
|
+
scheme: scheme
|
41
|
+
}
|
42
|
+
|
43
|
+
@check_boxes << CheckBoxInput.new(**args)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def scheme
|
49
|
+
@name ? :array : :boolean
|
37
50
|
end
|
38
51
|
end
|
39
52
|
end
|
@@ -5,11 +5,20 @@ module Primer
|
|
5
5
|
module Dsl
|
6
6
|
# :nodoc:
|
7
7
|
class CheckBoxInput < Input
|
8
|
-
|
8
|
+
DEFAULT_SCHEME = :boolean
|
9
|
+
SCHEMES = [DEFAULT_SCHEME, :array].freeze
|
10
|
+
|
11
|
+
attr_reader :name, :label, :value, :scheme
|
12
|
+
|
13
|
+
def initialize(name:, label:, value: nil, scheme: DEFAULT_SCHEME, **system_arguments)
|
14
|
+
raise ArgumentError, "Check box scheme must be one of #{SCHEMES.join(', ')}" unless SCHEMES.include?(scheme)
|
15
|
+
|
16
|
+
raise ArgumentError, "Check box needs an explicit value if scheme is array" if scheme == :array && value.nil?
|
9
17
|
|
10
|
-
def initialize(name:, label:, **system_arguments)
|
11
18
|
@name = name
|
12
19
|
@label = label
|
20
|
+
@value = value
|
21
|
+
@scheme = scheme
|
13
22
|
|
14
23
|
super(**system_arguments)
|
15
24
|
end
|
@@ -21,6 +30,16 @@ module Primer
|
|
21
30
|
def type
|
22
31
|
:check_box
|
23
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def caption_template_name
|
37
|
+
@caption_template_name ||= if @scheme == :array
|
38
|
+
:"#{name}_#{value}"
|
39
|
+
else
|
40
|
+
name.to_sym
|
41
|
+
end
|
42
|
+
end
|
24
43
|
end
|
25
44
|
end
|
26
45
|
end
|
data/lib/tasks/coverage.rake
CHANGED
data/lib/tasks/docs.rake
CHANGED
@@ -131,7 +131,7 @@ namespace :docs do
|
|
131
131
|
f.puts("componentId: #{data[:component_id]}")
|
132
132
|
f.puts("status: #{data[:status]}")
|
133
133
|
f.puts("source: #{data[:source]}")
|
134
|
-
f.puts("
|
134
|
+
f.puts("lookbook: #{data[:lookbook]}") if preview_exists?(component)
|
135
135
|
f.puts("---")
|
136
136
|
f.puts
|
137
137
|
f.puts("import Example from '#{data[:example_path]}'")
|
@@ -276,8 +276,8 @@ namespace :docs do
|
|
276
276
|
raise
|
277
277
|
end
|
278
278
|
|
279
|
-
File.open("static/arguments.
|
280
|
-
f.puts
|
279
|
+
File.open("static/arguments.json", "w") do |f|
|
280
|
+
f.puts JSON.pretty_generate(args_for_components)
|
281
281
|
end
|
282
282
|
|
283
283
|
# Build system arguments docs from BaseComponent
|
@@ -371,27 +371,25 @@ namespace :docs do
|
|
371
371
|
|
372
372
|
yard_example_tags = initialize_method.tags(:example)
|
373
373
|
|
374
|
-
path = Pathname.new("test/previews/
|
374
|
+
path = Pathname.new("test/previews/docs/#{short_name.underscore}_preview.rb")
|
375
375
|
path.dirname.mkdir unless path.dirname.exist?
|
376
376
|
|
377
377
|
File.open(path, "w") do |f|
|
378
|
-
f.puts("module
|
379
|
-
f.puts("
|
380
|
-
f.puts(" class #{short_name}Preview < ViewComponent::Preview")
|
378
|
+
f.puts("module Docs")
|
379
|
+
f.puts(" class #{short_name}Preview < ViewComponent::Preview")
|
381
380
|
|
382
381
|
yard_example_tags.each_with_index do |tag, index|
|
383
382
|
name, _, code = parse_example_tag(tag)
|
384
383
|
method_name = name.split("|").first.downcase.parameterize.underscore
|
385
|
-
f.puts("
|
384
|
+
f.puts(" def #{method_name}; end")
|
386
385
|
f.puts unless index == yard_example_tags.size - 1
|
387
|
-
path = Pathname.new("test/previews/
|
386
|
+
path = Pathname.new("test/previews/docs/#{short_name.underscore}_preview/#{method_name}.html.erb")
|
388
387
|
path.dirname.mkdir unless path.dirname.exist?
|
389
388
|
File.open(path, "w") do |view_file|
|
390
389
|
view_file.puts(code.to_s)
|
391
390
|
end
|
392
391
|
end
|
393
392
|
|
394
|
-
f.puts(" end")
|
395
393
|
f.puts(" end")
|
396
394
|
f.puts("end")
|
397
395
|
end
|
@@ -399,7 +397,7 @@ namespace :docs do
|
|
399
397
|
end
|
400
398
|
|
401
399
|
def generate_yard_registry
|
402
|
-
ENV["
|
400
|
+
ENV["RAILS_ENV"] = "test"
|
403
401
|
require File.expand_path("./../../demo/config/environment.rb", __dir__)
|
404
402
|
require "primer/view_components"
|
405
403
|
require "yard/docs_helper"
|
@@ -465,7 +463,7 @@ namespace :docs do
|
|
465
463
|
component_id: short_name.underscore,
|
466
464
|
status: status.capitalize,
|
467
465
|
source: source_url(component),
|
468
|
-
|
466
|
+
lookbook: lookbook_url(component),
|
469
467
|
path: "docs/content/components/#{status_path}#{short_name.downcase}.md",
|
470
468
|
example_path: example_path(component),
|
471
469
|
require_js_path: require_js_path(component)
|
@@ -478,10 +476,16 @@ namespace :docs do
|
|
478
476
|
"https://github.com/primer/view_components/tree/main/app/components/#{path}.rb"
|
479
477
|
end
|
480
478
|
|
481
|
-
def
|
482
|
-
path = component.name.
|
479
|
+
def lookbook_url(component)
|
480
|
+
path = component.name.underscore.gsub("_component", "")
|
483
481
|
|
484
|
-
"https://primer.style/view-components/
|
482
|
+
"https://primer.style/view-components/lookbook/inspect/#{path}/default/"
|
483
|
+
end
|
484
|
+
|
485
|
+
def preview_exists?(component)
|
486
|
+
path = component.name.underscore
|
487
|
+
|
488
|
+
File.exist?("test/previews/#{path}_preview.rb")
|
485
489
|
end
|
486
490
|
|
487
491
|
def example_path(component)
|
data/lib/tasks/static.rake
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
namespace :static do
|
4
4
|
task :dump do
|
5
|
-
ENV["
|
5
|
+
ENV["RAILS_ENV"] = "test"
|
6
6
|
require File.expand_path("./../../demo/config/environment.rb", __dir__)
|
7
7
|
require "primer/view_components"
|
8
8
|
# Loads all components for `.descendants` to work properly
|
data/lib/tasks/test.rake
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rake/testtask"
|
4
|
+
|
5
|
+
namespace :test do
|
6
|
+
desc "Run all tests"
|
7
|
+
task all: [:fast, :system]
|
8
|
+
|
9
|
+
Rake::TestTask.new(:single) do |t|
|
10
|
+
ENV["TZ"] = "Asia/Taipei"
|
11
|
+
|
12
|
+
t.libs << "test"
|
13
|
+
t.libs << "lib"
|
14
|
+
t.test_files = FileList[ENV["TESTS"]]
|
15
|
+
end
|
16
|
+
|
17
|
+
Rake::TestTask.new(:fast) do |t|
|
18
|
+
ENV["TZ"] = "Asia/Taipei"
|
19
|
+
|
20
|
+
t.libs << "test"
|
21
|
+
t.libs << "lib"
|
22
|
+
t.test_files = FileList[
|
23
|
+
"test/components/**/*_test.rb",
|
24
|
+
"test/lib/**/*_test.rb",
|
25
|
+
"test/primer/**/*_test.rb",
|
26
|
+
"test/linters/**/*_test.rb",
|
27
|
+
"test/rubocop/**/*_test.rb"
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
Rake::TestTask.new(:system) do |t|
|
32
|
+
ENV["TZ"] = "Asia/Taipei"
|
33
|
+
|
34
|
+
t.libs << "test"
|
35
|
+
t.libs << "lib"
|
36
|
+
t.test_files = FileList["test/system/**/*_test.rb", "test/previews/**/*_test.rb"]
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::TestTask.new(:bench) do |t|
|
40
|
+
t.libs << "test"
|
41
|
+
t.test_files = FileList["test/benchmarks/**/bench_*.rb"]
|
42
|
+
t.verbose = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
task :test do
|
47
|
+
if ENV["TESTS"]
|
48
|
+
Rake::Task["test:single"].invoke
|
49
|
+
else
|
50
|
+
Rake::Task["test:all"].invoke
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
task bench: "test:bench"
|