openproject-primer_view_components 0.34.0 → 0.35.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/CHANGELOG.md +26 -0
- data/app/assets/javascripts/lib/primer/forms/primer_text_field.d.ts +27 -0
- 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/alpha/action_menu/action_menu_element.js +13 -43
- data/app/components/primer/alpha/action_menu/action_menu_element.ts +13 -51
- data/app/components/primer/alpha/tab_nav.css +1 -1
- data/app/components/primer/alpha/tab_nav.css.json +2 -0
- data/app/components/primer/alpha/tab_nav.css.map +1 -1
- data/app/components/primer/alpha/tab_nav.pcss +11 -1
- data/app/components/primer/alpha/tab_panels.html.erb +5 -9
- data/app/components/primer/alpha/tab_panels.rb +4 -13
- data/app/components/primer/alpha/text_field.rb +1 -0
- data/app/components/primer/alpha/underline_nav.css +1 -1
- data/app/components/primer/alpha/underline_nav.css.json +2 -0
- data/app/components/primer/alpha/underline_nav.css.map +1 -1
- data/app/components/primer/alpha/underline_nav.pcss +7 -1
- data/app/components/primer/alpha/underline_panels.css +1 -0
- data/app/components/primer/alpha/underline_panels.css.json +6 -0
- data/app/components/primer/alpha/underline_panels.css.map +1 -0
- data/app/components/primer/alpha/underline_panels.html.erb +6 -8
- data/app/components/primer/alpha/underline_panels.pcss +4 -0
- data/app/components/primer/alpha/underline_panels.rb +6 -14
- data/app/components/primer/beta/icon_button.rb +5 -0
- data/app/components/primer/beta/relative_time.rb +3 -0
- data/app/components/primer/beta/spinner.html.erb +3 -0
- data/app/components/primer/beta/spinner.rb +15 -1
- data/app/components/primer/open_project/flex_layout.rb +1 -1
- data/app/components/primer/primer.pcss +1 -0
- data/lib/primer/forms/dsl/text_field_input.rb +8 -1
- data/lib/primer/forms/primer_text_field.d.ts +27 -0
- data/lib/primer/forms/primer_text_field.js +17 -5
- data/lib/primer/forms/primer_text_field.ts +24 -5
- data/lib/primer/forms/text_field.html.erb +6 -2
- data/lib/primer/view_components/version.rb +2 -2
- data/previews/primer/alpha/text_field_preview.rb +11 -0
- data/previews/primer/beta/breadcrumbs_preview.rb +9 -0
- data/previews/primer/beta/icon_button_preview/summary_as_button.html.erb +12 -0
- data/previews/primer/beta/icon_button_preview.rb +95 -14
- data/previews/primer/beta/relative_time_preview/link_with_tooltip.html.erb +13 -0
- data/previews/primer/beta/relative_time_preview.rb +12 -0
- data/previews/primer/beta/spinner_preview.rb +2 -2
- data/static/arguments.json +12 -12
- data/static/constants.json +1 -0
- data/static/info_arch.json +78 -13
- data/static/previews.json +65 -0
- metadata +9 -3
@@ -15,7 +15,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
15
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
16
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
17
17
|
};
|
18
|
-
var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_inputName, _ActionMenuElement_invokerBeingClicked, _ActionMenuElement_softDisableItems, _ActionMenuElement_potentiallyDisallowActivation,
|
18
|
+
var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_inputName, _ActionMenuElement_invokerBeingClicked, _ActionMenuElement_softDisableItems, _ActionMenuElement_potentiallyDisallowActivation, _ActionMenuElement_isAnchorActivationViaSpace, _ActionMenuElement_isActivation, _ActionMenuElement_handleInvokerActivated, _ActionMenuElement_handleDialogItemActivated, _ActionMenuElement_handleItemActivated, _ActionMenuElement_handleIncludeFragmentReplaced, _ActionMenuElement_handleFocusOut, _ActionMenuElement_show, _ActionMenuElement_hide, _ActionMenuElement_isOpen, _ActionMenuElement_setDynamicLabel, _ActionMenuElement_updateInput, _ActionMenuElement_firstItem_get;
|
19
19
|
import { controller, target } from '@github/catalyst';
|
20
20
|
import '@oddbird/popover-polyfill';
|
21
21
|
const validSelectors = ['[role="menuitem"]', '[role="menuitemcheckbox"]', '[role="menuitemradio"]'];
|
@@ -152,18 +152,13 @@ let ActionMenuElement = class ActionMenuElement extends HTMLElement {
|
|
152
152
|
return;
|
153
153
|
}
|
154
154
|
}
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
// is called. While calling preventDefault() appears to have no effect on link navigation, it skips
|
159
|
-
// form submission. The code below therefore only calls preventDefault() if the button has been
|
160
|
-
// activated by the space key, and manually submits the form if the button is a submit button.
|
161
|
-
if (__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isKeyboardActivationViaSpace).call(this, event)) {
|
155
|
+
// Pressing the space key on a link will cause the page to scroll unless preventDefault() is called.
|
156
|
+
// We then click it manually to navigate.
|
157
|
+
if (__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isAnchorActivationViaSpace).call(this, event)) {
|
162
158
|
event.preventDefault();
|
163
|
-
|
164
|
-
item.closest('form')?.submit();
|
165
|
-
}
|
159
|
+
item.click();
|
166
160
|
}
|
161
|
+
__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_handleItemActivated).call(this, item);
|
167
162
|
return;
|
168
163
|
}
|
169
164
|
if (event.type === 'include-fragment-replaced') {
|
@@ -269,26 +264,18 @@ _ActionMenuElement_potentiallyDisallowActivation = function _ActionMenuElement_p
|
|
269
264
|
}
|
270
265
|
return false;
|
271
266
|
};
|
272
|
-
|
273
|
-
return
|
274
|
-
|
275
|
-
_ActionMenuElement_isKeyboardActivationViaEnter = function _ActionMenuElement_isKeyboardActivationViaEnter(event) {
|
276
|
-
return (event instanceof KeyboardEvent &&
|
277
|
-
event.type === 'keydown' &&
|
278
|
-
!(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
|
279
|
-
event.key === 'Enter');
|
280
|
-
};
|
281
|
-
_ActionMenuElement_isKeyboardActivationViaSpace = function _ActionMenuElement_isKeyboardActivationViaSpace(event) {
|
282
|
-
return (event instanceof KeyboardEvent &&
|
267
|
+
_ActionMenuElement_isAnchorActivationViaSpace = function _ActionMenuElement_isAnchorActivationViaSpace(event) {
|
268
|
+
return (event.target instanceof HTMLAnchorElement &&
|
269
|
+
event instanceof KeyboardEvent &&
|
283
270
|
event.type === 'keydown' &&
|
284
271
|
!(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
|
285
272
|
event.key === ' ');
|
286
273
|
};
|
287
|
-
_ActionMenuElement_isMouseActivation = function _ActionMenuElement_isMouseActivation(event) {
|
288
|
-
return event instanceof MouseEvent && event.type === 'click';
|
289
|
-
};
|
290
274
|
_ActionMenuElement_isActivation = function _ActionMenuElement_isActivation(event) {
|
291
|
-
|
275
|
+
// Some browsers fire MouseEvents (Firefox) and others fire PointerEvents (Chrome). Activating an item via
|
276
|
+
// enter or space counterintuitively fires one of these rather than a KeyboardEvent. Since PointerEvent
|
277
|
+
// inherits from MouseEvent, it is enough to check for MouseEvent here.
|
278
|
+
return (event instanceof MouseEvent && event.type === 'click') || __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isAnchorActivationViaSpace).call(this, event);
|
292
279
|
};
|
293
280
|
_ActionMenuElement_handleInvokerActivated = function _ActionMenuElement_handleInvokerActivated(event) {
|
294
281
|
event.preventDefault();
|
@@ -363,23 +350,6 @@ _ActionMenuElement_handleItemActivated = function _ActionMenuElement_handleItemA
|
|
363
350
|
detail: { item: item.parentElement, checked: this.isItemChecked(item.parentElement) },
|
364
351
|
}));
|
365
352
|
};
|
366
|
-
_ActionMenuElement_activateItem = function _ActionMenuElement_activateItem(event, item) {
|
367
|
-
const eventWillActivateByDefault = (event instanceof MouseEvent && event.type === 'click') ||
|
368
|
-
(event instanceof KeyboardEvent &&
|
369
|
-
event.type === 'keydown' &&
|
370
|
-
!(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
|
371
|
-
event.key === 'Enter');
|
372
|
-
// if the event will result in activating the current item by default, i.e. is a
|
373
|
-
// mouse click or keyboard enter, bail out
|
374
|
-
if (eventWillActivateByDefault)
|
375
|
-
return;
|
376
|
-
// otherwise, event will not result in activation by default, so we stop it and
|
377
|
-
// simulate a click
|
378
|
-
/* eslint-disable-next-line no-restricted-syntax */
|
379
|
-
event.stopPropagation();
|
380
|
-
const elem = item;
|
381
|
-
elem.click();
|
382
|
-
};
|
383
353
|
_ActionMenuElement_handleIncludeFragmentReplaced = function _ActionMenuElement_handleIncludeFragmentReplaced() {
|
384
354
|
if (__classPrivateFieldGet(this, _ActionMenuElement_instances, "a", _ActionMenuElement_firstItem_get))
|
385
355
|
__classPrivateFieldGet(this, _ActionMenuElement_instances, "a", _ActionMenuElement_firstItem_get).focus();
|
@@ -151,21 +151,9 @@ export class ActionMenuElement extends HTMLElement {
|
|
151
151
|
return false
|
152
152
|
}
|
153
153
|
|
154
|
-
#
|
155
|
-
return this.#isKeyboardActivationViaEnter(event) || this.#isKeyboardActivationViaSpace(event)
|
156
|
-
}
|
157
|
-
|
158
|
-
#isKeyboardActivationViaEnter(event: Event): boolean {
|
159
|
-
return (
|
160
|
-
event instanceof KeyboardEvent &&
|
161
|
-
event.type === 'keydown' &&
|
162
|
-
!(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
|
163
|
-
event.key === 'Enter'
|
164
|
-
)
|
165
|
-
}
|
166
|
-
|
167
|
-
#isKeyboardActivationViaSpace(event: Event): boolean {
|
154
|
+
#isAnchorActivationViaSpace(event: Event): boolean {
|
168
155
|
return (
|
156
|
+
event.target instanceof HTMLAnchorElement &&
|
169
157
|
event instanceof KeyboardEvent &&
|
170
158
|
event.type === 'keydown' &&
|
171
159
|
!(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
|
@@ -173,12 +161,11 @@ export class ActionMenuElement extends HTMLElement {
|
|
173
161
|
)
|
174
162
|
}
|
175
163
|
|
176
|
-
#isMouseActivation(event: Event): boolean {
|
177
|
-
return event instanceof MouseEvent && event.type === 'click'
|
178
|
-
}
|
179
|
-
|
180
164
|
#isActivation(event: Event): boolean {
|
181
|
-
|
165
|
+
// Some browsers fire MouseEvents (Firefox) and others fire PointerEvents (Chrome). Activating an item via
|
166
|
+
// enter or space counterintuitively fires one of these rather than a KeyboardEvent. Since PointerEvent
|
167
|
+
// inherits from MouseEvent, it is enough to check for MouseEvent here.
|
168
|
+
return (event instanceof MouseEvent && event.type === 'click') || this.#isAnchorActivationViaSpace(event)
|
182
169
|
}
|
183
170
|
|
184
171
|
handleEvent(event: Event) {
|
@@ -237,21 +224,15 @@ export class ActionMenuElement extends HTMLElement {
|
|
237
224
|
}
|
238
225
|
}
|
239
226
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
// Pressing the space key on a button or link will cause the page to scroll unless preventDefault()
|
244
|
-
// is called. While calling preventDefault() appears to have no effect on link navigation, it skips
|
245
|
-
// form submission. The code below therefore only calls preventDefault() if the button has been
|
246
|
-
// activated by the space key, and manually submits the form if the button is a submit button.
|
247
|
-
if (this.#isKeyboardActivationViaSpace(event)) {
|
227
|
+
// Pressing the space key on a link will cause the page to scroll unless preventDefault() is called.
|
228
|
+
// We then click it manually to navigate.
|
229
|
+
if (this.#isAnchorActivationViaSpace(event)) {
|
248
230
|
event.preventDefault()
|
249
|
-
|
250
|
-
if (item.getAttribute('type') === 'submit') {
|
251
|
-
item.closest('form')?.submit()
|
252
|
-
}
|
231
|
+
;(item as HTMLElement).click()
|
253
232
|
}
|
254
233
|
|
234
|
+
this.#handleItemActivated(item)
|
235
|
+
|
255
236
|
return
|
256
237
|
}
|
257
238
|
|
@@ -335,6 +316,7 @@ export class ActionMenuElement extends HTMLElement {
|
|
335
316
|
}
|
336
317
|
|
337
318
|
this.#updateInput()
|
319
|
+
|
338
320
|
this.dispatchEvent(
|
339
321
|
new CustomEvent('itemActivated', {
|
340
322
|
detail: {item: item.parentElement, checked: this.isItemChecked(item.parentElement)},
|
@@ -342,26 +324,6 @@ export class ActionMenuElement extends HTMLElement {
|
|
342
324
|
)
|
343
325
|
}
|
344
326
|
|
345
|
-
#activateItem(event: Event, item: Element) {
|
346
|
-
const eventWillActivateByDefault =
|
347
|
-
(event instanceof MouseEvent && event.type === 'click') ||
|
348
|
-
(event instanceof KeyboardEvent &&
|
349
|
-
event.type === 'keydown' &&
|
350
|
-
!(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
|
351
|
-
event.key === 'Enter')
|
352
|
-
|
353
|
-
// if the event will result in activating the current item by default, i.e. is a
|
354
|
-
// mouse click or keyboard enter, bail out
|
355
|
-
if (eventWillActivateByDefault) return
|
356
|
-
|
357
|
-
// otherwise, event will not result in activation by default, so we stop it and
|
358
|
-
// simulate a click
|
359
|
-
/* eslint-disable-next-line no-restricted-syntax */
|
360
|
-
event.stopPropagation()
|
361
|
-
const elem = item as HTMLElement
|
362
|
-
elem.click()
|
363
|
-
}
|
364
|
-
|
365
327
|
#handleIncludeFragmentReplaced() {
|
366
328
|
if (this.#firstItem) this.#firstItem.focus()
|
367
329
|
this.#softDisableItems()
|
@@ -1 +1 @@
|
|
1
|
-
.tabnav{border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal);margin-top:0}.tabnav-tabs{display:flex;margin-bottom:calc(var(--borderWidth-thin)*-1);overflow:
|
1
|
+
.tabnav{border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal);margin-top:0}.tabnav-tabs{display:flex;margin-bottom:calc(var(--borderWidth-thin)*-1);overflow:hidden}.tabnav::part(tablist-wrapper){border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal)}.tabnav-tab{background-color:initial;border:var(--borderWidth-thin) solid #0000;border-bottom:0;color:var(--fgColor-muted);display:inline-block;flex-shrink:0;font-size:var(--text-body-size-medium);line-height:23px;padding:var(--base-size-8) var(--control-medium-paddingInline-spacious);-webkit-text-decoration:none;text-decoration:none;transition:color .2s cubic-bezier(.3,0,.5,1)}.tabnav-tab.selected,.tabnav-tab[aria-current]:not([aria-current=false]),.tabnav-tab[aria-selected=true]{background-color:var(--bgColor-default);border-color:var(--borderColor-default);border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0;color:var(--fgColor-default)}.tabnav-tab.selected .octicon,.tabnav-tab[aria-current]:not([aria-current=false]) .octicon,.tabnav-tab[aria-selected=true] .octicon{color:inherit}.tabnav-tab:hover{color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition-duration:.1s}.tabnav-tab:focus,.tabnav-tab:focus-visible{border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0!important;outline-offset:-6px}.tabnav-tab .octicon,.tabnav-tab:active{color:var(--fgColor-muted)}.tabnav-tab .octicon{margin-right:var(--control-small-gap)}.tabnav-tab .Counter{color:inherit;margin-left:var(--control-small-gap)}tab-container .tabnav-tab{margin-bottom:-1px}.tabnav-extra{color:var(--fgColor-muted);display:inline-block;font-size:var(--text-body-size-small);margin-left:10px;padding-top:10px}.tabnav-extra>.octicon{margin-right:2px}a.tabnav-extra:hover{color:var(--fgColor-accent);-webkit-text-decoration:none;text-decoration:none}.tabnav-btn{margin-left:var(--controlStack-medium-gap-condensed)}
|
@@ -3,6 +3,7 @@
|
|
3
3
|
"selectors": [
|
4
4
|
".tabnav",
|
5
5
|
".tabnav-tabs",
|
6
|
+
".tabnav::part(tablist-wrapper)",
|
6
7
|
".tabnav-tab",
|
7
8
|
".tabnav-tab.selected",
|
8
9
|
".tabnav-tab[aria-current]:not([aria-current=false])",
|
@@ -16,6 +17,7 @@
|
|
16
17
|
".tabnav-tab .octicon",
|
17
18
|
".tabnav-tab:active",
|
18
19
|
".tabnav-tab .Counter",
|
20
|
+
"tab-container .tabnav-tab",
|
19
21
|
".tabnav-extra",
|
20
22
|
".tabnav-extra>.octicon",
|
21
23
|
"a.tabnav-extra:hover",
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["tab_nav.pcss"],"names":[],"mappings":"AAGA,QAGE,sEAAuE,CADvE,qCAAsC,CADtC,YAGF,CAEA,aACE,YAAa,CACb,8CAAiD,CACjD,
|
1
|
+
{"version":3,"sources":["tab_nav.pcss"],"names":[],"mappings":"AAGA,QAGE,sEAAuE,CADvE,qCAAsC,CADtC,YAGF,CAEA,aACE,YAAa,CACb,8CAAiD,CACjD,eACF,CAEA,+BAEE,sEAAuE,CADvE,qCAEF,CAEA,YAQE,wBAA6B,CAE7B,0CAAgB,CAAhB,eAAgB,CAJhB,0BAA2B,CAL3B,oBAAqB,CACrB,aAAc,CAEd,sCAAuC,CACvC,gBAAiB,CAFjB,uEAAwE,CAIxE,4BAAqB,CAArB,oBAAqB,CAIrB,4CAwCF,CAtCE,yGAIE,uCAAwC,CACxC,uCAAwC,CACxC,uEAAwE,CAHxE,4BAQF,CAHE,oIACE,aACF,CAGF,kBACE,4BAA6B,CAC7B,4BAAqB,CAArB,oBAAqB,CACrB,uBACF,CAEA,4CAEE,iFAAmF,CACnF,mBACF,CAMA,wCAHE,0BAMF,CAHA,qBACE,qCAEF,CAEA,qBAEE,aAAc,CADd,oCAEF,CAGF,0BACE,kBACF,CAQA,cAKE,0BAA2B,CAJ3B,oBAAqB,CAGrB,qCAAsC,CADtC,gBAAiB,CADjB,gBAQF,CAHE,uBACE,gBACF,CAKF,qBACE,2BAA4B,CAC5B,4BAAqB,CAArB,oBACF,CAOA,YACE,oDACF","file":"tab_nav.css","sourcesContent":["/* tabnav */\n\n/* Outer wrapper */\n.tabnav {\n margin-top: 0;\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);\n}\n\n.tabnav-tabs {\n display: flex;\n margin-bottom: calc(var(--borderWidth-thin) * -1);\n overflow: hidden;\n}\n\n.tabnav::part(tablist-wrapper) {\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);\n}\n\n.tabnav-tab {\n display: inline-block;\n flex-shrink: 0;\n padding: var(--base-size-8) var(--control-medium-paddingInline-spacious);\n font-size: var(--text-body-size-medium);\n line-height: 23px;\n color: var(--fgColor-muted);\n text-decoration: none;\n background-color: transparent;\n border: var(--borderWidth-thin) solid transparent;\n border-bottom: 0;\n transition: color 0.2s cubic-bezier(0.3, 0, 0.5, 1);\n\n &.selected,\n &[aria-selected='true'],\n &[aria-current]:not([aria-current='false']) {\n color: var(--fgColor-default);\n background-color: var(--bgColor-default); /* cover bottom border */\n border-color: var(--borderColor-default);\n border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0;\n\n & .octicon {\n color: inherit;\n }\n }\n\n &:hover {\n color: var(--fgColor-default);\n text-decoration: none;\n transition-duration: 0.1s;\n }\n\n &:focus,\n &:focus-visible {\n border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0 !important;\n outline-offset: -6px;\n }\n\n &:active {\n color: var(--fgColor-muted);\n }\n\n & .octicon {\n margin-right: var(--control-small-gap);\n color: var(--fgColor-muted);\n }\n\n & .Counter {\n margin-left: var(--control-small-gap);\n color: inherit;\n }\n}\n\ntab-container .tabnav-tab {\n margin-bottom: -1px;\n}\n\n\n/* Tabnav extras\n**\n** Tabnav extras are non-tab elements that sit in the tabnav. Usually they're\n** inline text or links. */\n\n.tabnav-extra {\n display: inline-block;\n padding-top: 10px;\n margin-left: 10px;\n font-size: var(--text-body-size-small);\n color: var(--fgColor-muted);\n\n & > .octicon {\n margin-right: 2px;\n }\n}\n\n/* When tabnav-extra are anchors\n** stylelint-disable-next-line selector-no-qualifying-type */\na.tabnav-extra:hover {\n color: var(--fgColor-accent);\n text-decoration: none;\n}\n\n/* Tabnav buttons\n**\n** For when there are multiple buttons, space them out appropriately. Requires\n** the buttons to be floated or inline-block. */\n\n.tabnav-btn {\n margin-left: var(--controlStack-medium-gap-condensed);\n}\n"]}
|
@@ -10,7 +10,12 @@
|
|
10
10
|
.tabnav-tabs {
|
11
11
|
display: flex;
|
12
12
|
margin-bottom: calc(var(--borderWidth-thin) * -1);
|
13
|
-
overflow:
|
13
|
+
overflow: hidden;
|
14
|
+
}
|
15
|
+
|
16
|
+
.tabnav::part(tablist-wrapper) {
|
17
|
+
margin-bottom: var(--stack-gap-normal);
|
18
|
+
border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);
|
14
19
|
}
|
15
20
|
|
16
21
|
.tabnav-tab {
|
@@ -66,6 +71,11 @@
|
|
66
71
|
}
|
67
72
|
}
|
68
73
|
|
74
|
+
tab-container .tabnav-tab {
|
75
|
+
margin-bottom: -1px;
|
76
|
+
}
|
77
|
+
|
78
|
+
|
69
79
|
/* Tabnav extras
|
70
80
|
**
|
71
81
|
** Tabnav extras are non-tab elements that sit in the tabnav. Usually they're
|
@@ -1,13 +1,9 @@
|
|
1
|
-
<%=
|
2
|
-
<%=
|
3
|
-
|
4
|
-
<%=
|
5
|
-
<% tabs.each do |tab| %>
|
6
|
-
<%= tab %>
|
7
|
-
<% end %>
|
8
|
-
<% end %>
|
9
|
-
<%= extra if @align == :right %>
|
1
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
|
+
<%= extra if @align == :left %>
|
3
|
+
<% tabs.each do |tab| %>
|
4
|
+
<%= tab %>
|
10
5
|
<% end %>
|
6
|
+
<%= extra if @align == :right %>
|
11
7
|
<% tabs.each do |tab| %>
|
12
8
|
<%= tab.panel %>
|
13
9
|
<% end %>
|
@@ -26,7 +26,7 @@ module Primer
|
|
26
26
|
Primer::Alpha::Navigation::Tab.new(
|
27
27
|
selected: selected,
|
28
28
|
with_panel: true,
|
29
|
-
list:
|
29
|
+
list: false,
|
30
30
|
panel_id: "panel-#{id}",
|
31
31
|
**system_arguments
|
32
32
|
)
|
@@ -43,23 +43,14 @@ module Primer
|
|
43
43
|
|
44
44
|
# @param label [String] Sets an `aria-label` that helps assistive technology users understand the purpose of the tabs.
|
45
45
|
# @param align [Symbol] <%= one_of(Primer::TabNavHelper::EXTRA_ALIGN_OPTIONS) %> - Defaults to <%= Primer::TabNavHelper::EXTRA_ALIGN_DEFAULT %>
|
46
|
-
# @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
|
47
|
-
# @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> for the `TabContainer` wrapper.
|
48
46
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
49
47
|
def initialize(label:, body_arguments: {}, wrapper_arguments: {}, **system_arguments)
|
50
48
|
@align = EXTRA_ALIGN_DEFAULT
|
51
|
-
@wrapper_arguments = wrapper_arguments
|
52
49
|
|
53
|
-
@system_arguments = deny_tag_argument(**system_arguments)
|
54
|
-
@system_arguments[:tag] = :
|
50
|
+
@system_arguments = { **deny_tag_argument(**system_arguments), **deny_tag_argument(**wrapper_arguments) }
|
51
|
+
@system_arguments[:tag] = :"tab-container"
|
55
52
|
@system_arguments[:classes] = tab_nav_classes(@system_arguments[:classes])
|
56
|
-
|
57
|
-
@body_arguments = deny_tag_argument(**body_arguments)
|
58
|
-
@body_arguments[:tag] = :ul
|
59
|
-
@body_arguments[:classes] = tab_nav_body_classes(@body_arguments[:classes])
|
60
|
-
|
61
|
-
@body_arguments[:role] = :tablist
|
62
|
-
@body_arguments[:"aria-label"] = label
|
53
|
+
@system_arguments[:"aria-label"] = label
|
63
54
|
end
|
64
55
|
|
65
56
|
def before_render
|
@@ -26,6 +26,7 @@ module Primer
|
|
26
26
|
# @param monospace [Boolean] If `true`, uses a monospace font for the input field.
|
27
27
|
# @param auto_check_src [String] When provided, makes a request to the given URL whenever the contents of the text field changes. If the server responds with a non-2xx status code, the response body is used as the validation message.
|
28
28
|
# @param leading_visual [Hash] Renders a leading visual icon before the text field's cursor. The hash will be passed to Primer's <%= link_to_component(Primer::Beta::Octicon) %> component.
|
29
|
+
# @param leading_spinner [Boolean] If `true`, a leading spinner will be included in the markup. The spinner can be shown via the `showLeadingSpinner()` JavaScript method, and hidden via `hideLeadingSpinner()`. If this argument is `true`, a leading visual must also be provided.
|
29
30
|
# @param show_clear_button [Boolean] Whether or not to include a clear button inside the input that clears the input's contents when clicked.
|
30
31
|
# @param clear_button_id [String] The HTML id attribute of the clear button.
|
31
32
|
end
|
@@ -1 +1 @@
|
|
1
|
-
.UnderlineNav{box-shadow:inset 0 -1px 0 var(--borderColor-muted);display:flex;min-height:var(--base-size-48);overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:auto;justify-content:space-between}.UnderlineNav .Counter{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted));color:var(--fgColor-default);margin-left:var(--control-medium-gap)}.UnderlineNav .Counter--primary{background-color:var(--bgColor-neutral-emphasis);color:var(--fgColor-onEmphasis)}.UnderlineNav-body{align-items:center;display:flex;gap:var(--control-medium-gap);list-style:none}.UnderlineNav-item{align-items:center;background-color:initial;border:0;border-radius:var(--borderRadius-medium);color:var(--fgColor-default);cursor:pointer;display:flex;font-size:var(--text-body-size-medium);line-height:30px;padding:0 var(--control-medium-paddingInline-condensed);position:relative;text-align:center;white-space:nowrap}.UnderlineNav-item:focus,.UnderlineNav-item:focus-visible,.UnderlineNav-item:hover{border-bottom-color:var(--borderColor-neutral-muted);color:var(--fgColor-default);outline-offset:-2px;-webkit-text-decoration:none;text-decoration:none;transition:border-bottom-color .12s ease-out}.UnderlineNav-item [data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold);height:0;visibility:hidden}.UnderlineNav-item:before{content:"";height:100%;left:50%;min-height:48px;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}@media (pointer:fine){.UnderlineNav-item:hover{background:var(--control-transparent-bgColor-hover);color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition:background .12s ease-out}}.UnderlineNav-item.selected,.UnderlineNav-item[aria-current]:not([aria-current=false]),.UnderlineNav-item[role=tab][aria-selected=true]{border-bottom-color:var(--underlineNav-borderColor-active);color:var(--fgColor-default);font-weight:var(--base-text-weight-semibold)}.UnderlineNav-item.selected:after,.UnderlineNav-item[aria-current]:not([aria-current=false]):after,.UnderlineNav-item[role=tab][aria-selected=true]:after{background:var(--underlineNav-borderColor-active);border-radius:var(--borderRadius-medium);bottom:calc(50% - 25px);content:"";height:2px;position:absolute;right:50%;transform:translate(50%,-50%);width:100%;z-index:1}.UnderlineNav--right{justify-content:flex-end}.UnderlineNav--right .UnderlineNav-actions{flex:1 1 auto}.UnderlineNav-actions{align-self:center}.UnderlineNav--full{display:block}.UnderlineNav--full .UnderlineNav-body{min-height:var(--base-size-48)}.UnderlineNav-octicon{color:var(--fgColor-muted);display:inline!important;margin-right:var(--control-medium-gap);fill:var(--fgColor-muted)}.UnderlineNav-container{display:flex;justify-content:space-between}
|
1
|
+
.UnderlineNav{box-shadow:inset 0 -1px 0 var(--borderColor-muted);display:flex;min-height:var(--base-size-48);overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:auto;justify-content:space-between}.UnderlineNav .Counter{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted));color:var(--fgColor-default);margin-left:var(--control-medium-gap)}.UnderlineNav .Counter--primary{background-color:var(--bgColor-neutral-emphasis);color:var(--fgColor-onEmphasis)}.UnderlineNav::part(tablist-wrapper){box-shadow:inset 0 -1px 0 var(--borderColor-muted);padding:var(--control-medium-gap) 0;width:100%}.UnderlineNav-body,.UnderlineNav::part(tablist){align-items:center;display:flex;gap:var(--control-medium-gap);list-style:none}.UnderlineNav-item{align-items:center;background-color:initial;border:0;border-radius:var(--borderRadius-medium);color:var(--fgColor-default);cursor:pointer;display:flex;font-size:var(--text-body-size-medium);line-height:30px;padding:0 var(--control-medium-paddingInline-condensed);position:relative;text-align:center;white-space:nowrap}.UnderlineNav-item:focus,.UnderlineNav-item:focus-visible,.UnderlineNav-item:hover{border-bottom-color:var(--borderColor-neutral-muted);color:var(--fgColor-default);outline-offset:-2px;-webkit-text-decoration:none;text-decoration:none;transition:border-bottom-color .12s ease-out}.UnderlineNav-item [data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold);height:0;visibility:hidden}.UnderlineNav-item:before{content:"";height:100%;left:50%;min-height:48px;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}@media (pointer:fine){.UnderlineNav-item:hover{background:var(--control-transparent-bgColor-hover);color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition:background .12s ease-out}}.UnderlineNav-item.selected,.UnderlineNav-item[aria-current]:not([aria-current=false]),.UnderlineNav-item[role=tab][aria-selected=true]{border-bottom-color:var(--underlineNav-borderColor-active);color:var(--fgColor-default);font-weight:var(--base-text-weight-semibold)}.UnderlineNav-item.selected:after,.UnderlineNav-item[aria-current]:not([aria-current=false]):after,.UnderlineNav-item[role=tab][aria-selected=true]:after{background:var(--underlineNav-borderColor-active);border-radius:var(--borderRadius-medium);bottom:calc(50% - 25px);content:"";height:2px;position:absolute;right:50%;transform:translate(50%,-50%);width:100%;z-index:1}.UnderlineNav--right{justify-content:flex-end}.UnderlineNav--right .UnderlineNav-actions{flex:1 1 auto}.UnderlineNav-actions{align-self:center}.UnderlineNav--full{display:block}.UnderlineNav--full .UnderlineNav-body{min-height:var(--base-size-48)}.UnderlineNav-octicon{color:var(--fgColor-muted);display:inline!important;margin-right:var(--control-medium-gap);fill:var(--fgColor-muted)}.UnderlineNav-container{display:flex;justify-content:space-between}
|
@@ -4,7 +4,9 @@
|
|
4
4
|
".UnderlineNav",
|
5
5
|
".UnderlineNav .Counter",
|
6
6
|
".UnderlineNav .Counter--primary",
|
7
|
+
".UnderlineNav::part(tablist-wrapper)",
|
7
8
|
".UnderlineNav-body",
|
9
|
+
".UnderlineNav::part(tablist)",
|
8
10
|
".UnderlineNav-item",
|
9
11
|
".UnderlineNav-item:focus",
|
10
12
|
".UnderlineNav-item:focus-visible",
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["underline_nav.pcss","<no source>"],"names":[],"mappings":"AAEA,cAKE,kDAAmD,CAJnD,YAAa,CACb,8BAA+B,CAC/B,eAAgB,CAChB,iBAAkB,CAElB,+BAAgC,CAChC,6BAYF,CAVE,uBAGE,wEAA0E,CAD1E,4BAA6B,CAD7B,qCAGF,CAEA,gCAEE,gDAAiD,CADjD,+BAEF,CAGF,
|
1
|
+
{"version":3,"sources":["underline_nav.pcss","<no source>"],"names":[],"mappings":"AAEA,cAKE,kDAAmD,CAJnD,YAAa,CACb,8BAA+B,CAC/B,eAAgB,CAChB,iBAAkB,CAElB,+BAAgC,CAChC,6BAYF,CAVE,uBAGE,wEAA0E,CAD1E,4BAA6B,CAD7B,qCAGF,CAEA,gCAEE,gDAAiD,CADjD,+BAEF,CAGF,qCAEE,kDAAmD,CACnD,mCAAoC,CAFpC,UAGF,CAEA,gDAEE,kBAAmB,CADnB,YAAa,CAEb,6BAA8B,CAC9B,eACF,CAEA,mBAaE,kBAAmB,CAHnB,wBAA6B,CAC7B,QAAS,CACT,wCAAyC,CANzC,4BAA6B,CAG7B,cAAe,CAPf,YAAa,CAEb,sCAAuC,CACvC,gBAAiB,CAFjB,uDAAwD,CAFxD,iBAAkB,CAMlB,iBAAkB,CAClB,kBA8DF,CAvDE,mFAKE,oDAAqD,CAFrD,4BAA6B,CAG7B,mBAAoB,CAFpB,4BAAqB,CAArB,oBAAqB,CAGrB,4CACF,CAGA,yCAKE,0BAA2B,CAJ3B,aAAc,CAEd,4CAA6C,CAD7C,QAAS,CAET,iBAEF,CAIE,0BCxEJ,WAAA,YAAA,SAAA,gBAAA,kBAAA,QAAA,4CAAA,UDwE8B,CAI5B,sBACE,yBAGE,mDAAoD,CAFpD,4BAA6B,CAC7B,4BAAqB,CAArB,oBAAqB,CAErB,mCACF,CACF,CAEA,wIAKE,0DAA2D,CAD3D,4BAA6B,CAD7B,4CAiBF,CAZE,0JAQE,iDAAkD,CAClD,wCAAyC,CALzC,uBAAwB,CAGxB,UAAW,CADX,UAAW,CALX,iBAAkB,CAElB,SAAU,CAOV,6BAA+B,CAL/B,UAAW,CAHX,SASF,CAIJ,qBACE,wBAKF,CAHE,2CACE,aACF,CAGF,sBACE,iBACF,CAEA,oBACE,aAMF,CAHE,uCACE,8BACF,CAGF,sBAGE,0BAA2B,CAF3B,wBAA0B,CAC1B,sCAAuC,CAEvC,yBACF,CAEA,wBACE,YAAa,CACb,6BACF","file":"underline_nav.css","sourcesContent":["/* UnderlineNav */\n\n.UnderlineNav {\n display: flex;\n min-height: var(--base-size-48);\n overflow-x: auto;\n overflow-y: hidden;\n box-shadow: inset 0 -1px 0 var(--borderColor-muted);\n -webkit-overflow-scrolling: auto;\n justify-content: space-between;\n\n & .Counter {\n margin-left: var(--control-medium-gap);\n color: var(--fgColor-default);\n background-color: var(--bgColor-neutral-muted, var(--color-neutral-muted));\n }\n\n & .Counter--primary {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-neutral-emphasis);\n }\n}\n\n.UnderlineNav::part(tablist-wrapper) {\n width: 100%;\n box-shadow: inset 0 -1px 0 var(--borderColor-muted);\n padding: var(--control-medium-gap) 0;\n}\n\n.UnderlineNav-body,.UnderlineNav::part(tablist) {\n display: flex;\n align-items: center;\n gap: var(--control-medium-gap);\n list-style: none;\n}\n\n.UnderlineNav-item {\n position: relative;\n display: flex;\n padding: 0 var(--control-medium-paddingInline-condensed);\n font-size: var(--text-body-size-medium);\n line-height: 30px;\n color: var(--fgColor-default);\n text-align: center;\n white-space: nowrap;\n cursor: pointer;\n background-color: transparent;\n border: 0;\n border-radius: var(--borderRadius-medium);\n align-items: center;\n\n &:hover,\n &:focus,\n &:focus-visible {\n color: var(--fgColor-default);\n text-decoration: none;\n border-bottom-color: var(--borderColor-neutral-muted);\n outline-offset: -2px;\n transition: border-bottom-color 0.12s ease-out;\n }\n\n /* renders a visibly hidden \"copy\" of the label in bold, reserving box space for when label becomes bold on selected */\n & [data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold);\n visibility: hidden;\n content: attr(data-content);\n }\n\n /* increase touch target area */\n &::before {\n @mixin minTouchTarget 48px;\n }\n\n /* hover state was \"sticking\" on mobile after click */\n @media (pointer: fine) {\n &:hover {\n color: var(--fgColor-default);\n text-decoration: none;\n background: var(--control-transparent-bgColor-hover);\n transition: background 0.12s ease-out;\n }\n }\n\n &.selected,\n &[role='tab'][aria-selected='true'],\n &[aria-current]:not([aria-current='false']) {\n font-weight: var(--base-text-weight-semibold);\n color: var(--fgColor-default);\n border-bottom-color: var(--underlineNav-borderColor-active);\n\n /* current/selected underline */\n &::after {\n position: absolute;\n z-index: 1; /* raise above full-width flash banner */\n right: 50%;\n bottom: calc(50% - 25px); /* 48px total height / 2 (24px) + 1px */\n width: 100%;\n height: 2px;\n content: '';\n background: var(--underlineNav-borderColor-active);\n border-radius: var(--borderRadius-medium);\n transform: translate(50%, -50%);\n }\n }\n}\n\n.UnderlineNav--right {\n justify-content: flex-end;\n\n & .UnderlineNav-actions {\n flex: 1 1 auto;\n }\n}\n\n.UnderlineNav-actions {\n align-self: center;\n}\n\n.UnderlineNav--full {\n display: block;\n\n /* required for underline to align with additional wrapper element */\n & .UnderlineNav-body {\n min-height: var(--base-size-48);\n }\n}\n\n.UnderlineNav-octicon {\n display: inline !important;\n margin-right: var(--control-medium-gap);\n color: var(--fgColor-muted);\n fill: var(--fgColor-muted);\n}\n\n.UnderlineNav-container {\n display: flex;\n justify-content: space-between;\n}\n",null]}
|
@@ -21,7 +21,13 @@
|
|
21
21
|
}
|
22
22
|
}
|
23
23
|
|
24
|
-
.UnderlineNav-
|
24
|
+
.UnderlineNav::part(tablist-wrapper) {
|
25
|
+
width: 100%;
|
26
|
+
box-shadow: inset 0 -1px 0 var(--borderColor-muted);
|
27
|
+
padding: var(--control-medium-gap) 0;
|
28
|
+
}
|
29
|
+
|
30
|
+
.UnderlineNav-body,.UnderlineNav::part(tablist) {
|
25
31
|
display: flex;
|
26
32
|
align-items: center;
|
27
33
|
gap: var(--control-medium-gap);
|
@@ -0,0 +1 @@
|
|
1
|
+
tab-container.UnderlineNav{box-shadow:none;flex-direction:column}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["underline_panels.pcss"],"names":[],"mappings":"AAAA,2BACE,eAAgB,CAChB,qBACF","file":"underline_panels.css","sourcesContent":["tab-container.UnderlineNav {\n box-shadow: none;\n flex-direction: column;\n}\n"]}
|
@@ -1,18 +1,16 @@
|
|
1
|
-
<%=
|
1
|
+
<%= render Primer::BaseComponent.new(**@wrapper_arguments) do %>
|
2
2
|
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
3
3
|
<% if @align == :right %>
|
4
4
|
<%= actions %>
|
5
5
|
<% end %>
|
6
|
-
|
7
|
-
|
8
|
-
<%= tab %>
|
9
|
-
<% end %>
|
6
|
+
<% tabs.each do |tab| %>
|
7
|
+
<%= tab %>
|
10
8
|
<% end %>
|
11
9
|
<% if @align == :left %>
|
12
10
|
<%= actions %>
|
13
11
|
<% end %>
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
<% tabs.each do |tab| %>
|
13
|
+
<%= tab.panel %>
|
14
|
+
<% end %>
|
17
15
|
<% end %>
|
18
16
|
<% end %>
|
@@ -18,7 +18,7 @@ module Primer
|
|
18
18
|
Primer::Alpha::Navigation::Tab.new(
|
19
19
|
selected: selected,
|
20
20
|
with_panel: true,
|
21
|
-
list:
|
21
|
+
list: false,
|
22
22
|
icon_classes: "UnderlineNav-octicon",
|
23
23
|
panel_id: "panel-#{id}",
|
24
24
|
**system_arguments
|
@@ -43,24 +43,16 @@ module Primer
|
|
43
43
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
44
44
|
def initialize(label:, align: ALIGN_DEFAULT, body_arguments: {}, wrapper_arguments: {}, **system_arguments)
|
45
45
|
@align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
|
46
|
-
@wrapper_arguments = wrapper_arguments
|
46
|
+
@wrapper_arguments = deny_tag_argument(**wrapper_arguments)
|
47
|
+
@wrapper_arguments[:tag] = :div
|
47
48
|
|
48
49
|
@system_arguments = deny_tag_argument(**system_arguments)
|
49
|
-
@system_arguments[:tag] = :
|
50
|
+
@system_arguments[:tag] = :"tab-container"
|
50
51
|
@system_arguments[:classes] = underline_nav_classes(@system_arguments[:classes], @align)
|
52
|
+
@system_arguments[:"aria-label"] = label
|
51
53
|
|
52
54
|
@body_arguments = deny_tag_argument(**body_arguments)
|
53
|
-
@body_arguments[:tag] = :
|
54
|
-
@body_arguments[:classes] = underline_nav_body_classes(@body_arguments[:classes])
|
55
|
-
|
56
|
-
@body_arguments[:role] = :tablist
|
57
|
-
@body_arguments[:"aria-label"] = label
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def body
|
63
|
-
Primer::BaseComponent.new(**@body_arguments)
|
55
|
+
@body_arguments[:tag] = :div
|
64
56
|
end
|
65
57
|
end
|
66
58
|
end
|
@@ -14,6 +14,11 @@ module Primer
|
|
14
14
|
# Either `aria-label` or `aria-description` will be used for the `Tooltip` text, depending on which one is present.
|
15
15
|
# Either `aria-label` or `aria-description` will be used for the `Tooltip` text, depending on which one is present.
|
16
16
|
# [Learn more about best functional image practices (WAI Images)](https://www.w3.org/WAI/tutorials/images/functional)
|
17
|
+
#
|
18
|
+
# Additional markup is required if setting the `tag` argument to either `:a` or `:summary`.
|
19
|
+
#
|
20
|
+
# * `:a` requires you to pass in an `href` attribute
|
21
|
+
# * `:summary` requires you to wrap the component in a `<details>` element
|
17
22
|
class IconButton < Primer::Component
|
18
23
|
status :beta
|
19
24
|
|
@@ -101,6 +101,7 @@ module Primer
|
|
101
101
|
# @param format_style [Symbol] The format the display should take. <%= one_of(Primer::Beta::RelativeTime::FORMAT_STYLE_OPTIONS) %>
|
102
102
|
# @param lang [string] The language to use.
|
103
103
|
# @param title [string] Provide a custom title to the element.
|
104
|
+
# @param no_title [Boolean] Removes the `title` attribute provided on the element by default.
|
104
105
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
105
106
|
def initialize(
|
106
107
|
datetime:,
|
@@ -120,6 +121,7 @@ module Primer
|
|
120
121
|
format_style: nil,
|
121
122
|
lang: nil,
|
122
123
|
title: nil,
|
124
|
+
no_title: false,
|
123
125
|
**system_arguments
|
124
126
|
)
|
125
127
|
@system_arguments = deny_tag_argument(**system_arguments)
|
@@ -137,6 +139,7 @@ module Primer
|
|
137
139
|
@system_arguments[:threshold] = threshold if threshold.present?
|
138
140
|
@system_arguments[:precision] = precision if precision.present?
|
139
141
|
@system_arguments[:title] = title if title.present?
|
142
|
+
@system_arguments[:"no-title"] = no_title if no_title
|
140
143
|
@system_arguments[:lang] = lang if lang.present?
|
141
144
|
@system_arguments[:format] = fetch_or_fallback(FORMAT_OPTIONS, format, FORMAT_DEFAULT) if format.present?
|
142
145
|
@system_arguments[:"format-style"] = format_style if format_style.present?
|
@@ -2,3 +2,6 @@
|
|
2
2
|
<circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" />
|
3
3
|
<path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" />
|
4
4
|
<% end %>
|
5
|
+
<% if no_aria_label? %>
|
6
|
+
<span class="sr-only"><%= @sr_text %></span>
|
7
|
+
<% end %>
|
@@ -12,6 +12,7 @@ module Primer
|
|
12
12
|
DEFAULT_SIZE => 32,
|
13
13
|
:large => 64
|
14
14
|
}.freeze
|
15
|
+
DEFAULT_SR_TEXT = "Loading"
|
15
16
|
|
16
17
|
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
17
18
|
|
@@ -22,7 +23,7 @@ module Primer
|
|
22
23
|
# @param size [Symbol] <%= one_of(Primer::Beta::Spinner::SIZE_MAPPINGS) %>
|
23
24
|
# @param style [String] Custom element styles.
|
24
25
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
25
|
-
def initialize(size: DEFAULT_SIZE, style: DEFAULT_STYLE, **system_arguments)
|
26
|
+
def initialize(size: DEFAULT_SIZE, style: DEFAULT_STYLE, sr_text: DEFAULT_SR_TEXT, **system_arguments)
|
26
27
|
@system_arguments = deny_tag_argument(**system_arguments)
|
27
28
|
@system_arguments[:tag] = :svg
|
28
29
|
@system_arguments[:style] ||= style
|
@@ -31,6 +32,19 @@ module Primer
|
|
31
32
|
@system_arguments[:height] = SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)]
|
32
33
|
@system_arguments[:viewBox] = "0 0 16 16"
|
33
34
|
@system_arguments[:fill] = :none
|
35
|
+
@system_arguments[:aria] ||= {}
|
36
|
+
@sr_text = sr_text
|
37
|
+
|
38
|
+
if no_aria_label?
|
39
|
+
@system_arguments[:aria][:hidden] = true
|
40
|
+
else
|
41
|
+
@system_arguments[:role] = "img"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def no_aria_label?
|
46
|
+
!@system_arguments[:aria][:label] && !@system_arguments[:"aria-label"] &&
|
47
|
+
!@system_arguments[:aria][:labelledby] && !@system_arguments[:"aria-labelledby"]
|
34
48
|
end
|
35
49
|
end
|
36
50
|
end
|
@@ -29,7 +29,7 @@ module Primer
|
|
29
29
|
|
30
30
|
def render?
|
31
31
|
# no slot provided
|
32
|
-
|
32
|
+
return false if rows.empty? && columns.empty? && boxes.empty?
|
33
33
|
|
34
34
|
if [rows, columns, boxes].count { |arr| !arr.empty? } == 1
|
35
35
|
# only rows or columns or boxes are used
|
@@ -7,17 +7,20 @@ module Primer
|
|
7
7
|
class TextFieldInput < Input
|
8
8
|
attr_reader(
|
9
9
|
*%i[
|
10
|
-
name label show_clear_button leading_visual clear_button_id
|
10
|
+
name label show_clear_button leading_visual leading_spinner clear_button_id
|
11
11
|
visually_hide_label inset monospace field_wrap_classes auto_check_src
|
12
12
|
]
|
13
13
|
)
|
14
14
|
|
15
|
+
alias leading_spinner? leading_spinner
|
16
|
+
|
15
17
|
def initialize(name:, label:, **system_arguments)
|
16
18
|
@name = name
|
17
19
|
@label = label
|
18
20
|
|
19
21
|
@show_clear_button = system_arguments.delete(:show_clear_button)
|
20
22
|
@leading_visual = system_arguments.delete(:leading_visual)
|
23
|
+
@leading_spinner = !!system_arguments.delete(:leading_spinner)
|
21
24
|
@clear_button_id = system_arguments.delete(:clear_button_id)
|
22
25
|
@inset = system_arguments.delete(:inset)
|
23
26
|
@monospace = system_arguments.delete(:monospace)
|
@@ -30,6 +33,10 @@ module Primer
|
|
30
33
|
)
|
31
34
|
end
|
32
35
|
|
36
|
+
if @leading_spinner && !@leading_visual
|
37
|
+
raise ArgumentError, "text fields that request a leading spinner must also specify a leading visual"
|
38
|
+
end
|
39
|
+
|
33
40
|
super(**system_arguments)
|
34
41
|
|
35
42
|
add_input_data(:target, "primer-text-field.inputElement #{system_arguments.dig(:data, :target) || ''}")
|