@inglorious/ui 9.7.3 → 9.8.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.
- package/package.json +5 -5
- package/src/controls/button/style.css +0 -2
- package/src/controls/button/template.js +2 -3
- package/src/controls/checkbox/style.css +0 -1
- package/src/controls/checkbox/template.js +0 -2
- package/src/controls/combobox/style.css +0 -14
- package/src/controls/combobox/template.js +0 -13
- package/src/controls/file-upload/template.js +1 -1
- package/src/controls/image-cropper/helpers.js +0 -2
- package/src/controls/image-cropper/image.js +0 -2
- package/src/controls/image-cropper/style.css +0 -6
- package/src/controls/image-cropper/template.js +3 -5
- package/src/controls/input/style.css +0 -1
- package/src/controls/radio-group/style.css +0 -2
- package/src/controls/rating/style.css +0 -3
- package/src/controls/select/style.css +0 -6
- package/src/controls/slider/style.css +0 -5
- package/src/controls/slider/template.js +0 -1
- package/src/controls/switch/style.css +0 -1
- package/src/controls/switch/template.js +0 -2
- package/src/controls/textarea/style.css +0 -2
- package/src/data-display/before-after/style.css +0 -4
- package/src/data-display/before-after/template.js +3 -3
- package/src/data-display/carousel/carousel.stories.js +0 -2
- package/src/data-display/carousel/handlers.js +0 -2
- package/src/data-display/carousel/style.css +0 -18
- package/src/data-display/carousel/template.js +0 -15
- package/src/data-display/chat/index.js +0 -1
- package/src/data-display/chat/style.css +0 -2
- package/src/data-display/chat/template.js +0 -1
- package/src/data-display/chip/template.js +0 -1
- package/src/data-display/data-grid/base.css +0 -2
- package/src/data-display/data-grid/handlers.js +1 -8
- package/src/data-display/data-grid/helpers.js +0 -5
- package/src/data-display/data-grid/template.js +0 -1
- package/src/data-display/data-grid/theme.css +0 -1
- package/src/data-display/icon/style.css +0 -7
- package/src/data-display/icon/template.js +2 -2
- package/src/data-display/table/style.css +0 -2
- package/src/data-display/tooltip/style.css +0 -3
- package/src/data-display/virtual-list/handlers.js +0 -2
- package/src/data-display/virtual-list/template.js +2 -4
- package/src/examples/dashboard/before-after-data.js +0 -3
- package/src/examples/dashboard/data.js +0 -1
- package/src/examples/dashboard/primitive-content.js +0 -2
- package/src/examples/dashboard/style.css +0 -3
- package/src/feedback/alert/style.css +0 -1
- package/src/feedback/dialog/dialog.stories.js +7 -2
- package/src/feedback/dialog/style.css +31 -18
- package/src/feedback/dialog/template.js +16 -16
- package/src/feedback/progress/style.css +0 -6
- package/src/feedback/progress/template.js +0 -3
- package/src/feedback/snackbar/snackbar.stories.js +0 -1
- package/src/feedback/snackbar/style.css +0 -10
- package/src/layout/flex/style.css +0 -2
- package/src/navigation/bottom-navigation/style.css +0 -7
- package/src/navigation/drawer/style.css +0 -21
- package/src/navigation/drawer/template.js +10 -9
- package/src/navigation/menu/menu.stories.js +0 -2
- package/src/navigation/menu/style.css +0 -4
- package/src/navigation/menu/template.js +0 -3
- package/src/navigation/speed-dial/style.css +0 -4
- package/src/navigation/speed-dial/template.js +0 -5
- package/src/navigation/tabs/template.js +0 -2
- package/src/navigation/view-transitions/index.js +0 -13
- package/src/navigation/view-transitions/style.css +0 -2
- package/src/shared/icons.js +0 -4
- package/src/styles/themes/bootstrap.css +0 -40
- package/src/styles/themes/inglorious.css +0 -21
- package/src/styles/themes/ios-18.css +0 -47
- package/src/styles/themes/ios-26.css +0 -55
- package/src/styles/themes/material-3.css +0 -52
- package/src/styles/themes/material-ui.css +0 -43
- package/src/styles/tokens.css +0 -40
- package/src/surfaces/accordion/style.css +0 -2
- package/src/surfaces/accordion/template.js +0 -4
- package/src/surfaces/app-bar/style.css +0 -3
- package/src/surfaces/card/style.css +0 -3
- package/types/controls/button-group.d.ts +5 -3
- package/types/controls/button.d.ts +3 -1
- package/types/controls/combobox.d.ts +13 -0
- package/types/controls/fab.d.ts +1 -1
- package/types/controls/icon-button.d.ts +7 -21
- package/types/controls/input.d.ts +2 -2
- package/types/data-display/avatar.d.ts +1 -1
- package/types/data-display/badge.d.ts +4 -2
- package/types/data-display/chip.d.ts +5 -3
- package/types/data-display/icon.d.ts +4 -2
- package/types/data-display/tooltip.d.ts +4 -2
- package/types/data-display/typography.d.ts +3 -1
- package/types/feedback/alert.d.ts +3 -1
- package/types/feedback/backdrop.d.ts +4 -2
- package/types/feedback/dialog.d.ts +11 -1
- package/types/index.d.ts +1 -0
- package/types/layout/container.d.ts +3 -1
- package/types/layout/flex.d.ts +9 -11
- package/types/layout/grid.d.ts +4 -2
- package/types/navigation/breadcrumbs.d.ts +1 -1
- package/types/navigation/drawer.d.ts +9 -1
- package/types/navigation/link.d.ts +4 -2
- package/types/shared/renderable.d.ts +12 -0
- package/types/surfaces/app-bar.d.ts +3 -1
- package/types/surfaces/card.d.ts +4 -2
- package/types/surfaces/paper.d.ts +3 -1
|
@@ -167,7 +167,6 @@ export const Chat = {
|
|
|
167
167
|
isFullWidth: true,
|
|
168
168
|
onChange: (value) => props.onDraftChange?.(value),
|
|
169
169
|
onKeyDown: (event) => {
|
|
170
|
-
// Enter sends, unless it closes a character being composed.
|
|
171
170
|
if (event.key !== "Enter" || event.shiftKey || event.isComposing) {
|
|
172
171
|
return
|
|
173
172
|
}
|
|
@@ -38,7 +38,6 @@ export function render(props) {
|
|
|
38
38
|
() => html`<span class="iw-chip-icon" aria-hidden="true">${icon}</span>`,
|
|
39
39
|
)} <span class="iw-chip-label">${children}</span>`
|
|
40
40
|
|
|
41
|
-
// A chip that can be picked is a toggle button, pressed while selected.
|
|
42
41
|
if (isSelected !== undefined) {
|
|
43
42
|
return html`<button
|
|
44
43
|
type="button"
|
|
@@ -37,16 +37,13 @@ export function sortChange(entity, columnId) {
|
|
|
37
37
|
const existingIndex = entity.sorts.findIndex((s) => s.column === columnId)
|
|
38
38
|
|
|
39
39
|
if (existingIndex !== -1) {
|
|
40
|
-
// Toggle direction
|
|
41
40
|
const existing = entity.sorts[existingIndex]
|
|
42
41
|
if (existing.direction === "asc") {
|
|
43
42
|
existing.direction = "desc"
|
|
44
43
|
} else {
|
|
45
|
-
// Remove from sort if going from desc back to nothing
|
|
46
44
|
entity.sorts.splice(existingIndex, 1)
|
|
47
45
|
}
|
|
48
46
|
} else {
|
|
49
|
-
// Add new sort
|
|
50
47
|
entity.sorts.push({ column: columnId, direction: "asc" })
|
|
51
48
|
}
|
|
52
49
|
|
|
@@ -201,7 +198,7 @@ export function rowToggle(entity, rowId) {
|
|
|
201
198
|
|
|
202
199
|
if (index === -1) {
|
|
203
200
|
if (!entity.isMultiSelect) {
|
|
204
|
-
entity.selection = [rowId]
|
|
201
|
+
entity.selection = [rowId]
|
|
205
202
|
} else {
|
|
206
203
|
entity.selection.push(rowId)
|
|
207
204
|
}
|
|
@@ -251,14 +248,12 @@ export function rowsToggleAll(entity) {
|
|
|
251
248
|
)
|
|
252
249
|
|
|
253
250
|
if (allSelected) {
|
|
254
|
-
// Deselect all visible
|
|
255
251
|
rows.forEach((row) => {
|
|
256
252
|
const rowId = getRowKeyValue(entity, row)
|
|
257
253
|
const index = entity.selection.indexOf(rowId)
|
|
258
254
|
if (index !== -1) entity.selection.splice(index, 1)
|
|
259
255
|
})
|
|
260
256
|
} else {
|
|
261
|
-
// Select all visible
|
|
262
257
|
rows.forEach((row) => {
|
|
263
258
|
const rowId = getRowKeyValue(entity, row)
|
|
264
259
|
if (!entity.selection.includes(rowId)) {
|
|
@@ -398,7 +393,6 @@ function initDataGrid(entity) {
|
|
|
398
393
|
entity.rows ??= []
|
|
399
394
|
entity.rowId ??= "id"
|
|
400
395
|
|
|
401
|
-
// Auto-generate columns from first data item if not provided
|
|
402
396
|
if (!entity.columns && entity.rows.length) {
|
|
403
397
|
const [firstRow] = entity.rows
|
|
404
398
|
|
|
@@ -427,7 +421,6 @@ function initDataGrid(entity) {
|
|
|
427
421
|
})
|
|
428
422
|
}
|
|
429
423
|
|
|
430
|
-
// State
|
|
431
424
|
entity.sorts ??= []
|
|
432
425
|
entity.filters ??= {}
|
|
433
426
|
entity.search ??= null
|
|
@@ -196,12 +196,10 @@ function applyFilters(entity, rows) {
|
|
|
196
196
|
const column = entity.columns.find((c) => c.id === columnId)
|
|
197
197
|
if (!column) return true
|
|
198
198
|
|
|
199
|
-
// Custom filter function
|
|
200
199
|
if (column.filterFn) {
|
|
201
200
|
return column.filterFn(row, filterValue)
|
|
202
201
|
}
|
|
203
202
|
|
|
204
|
-
// Default filters by type
|
|
205
203
|
const value = row[columnId]
|
|
206
204
|
|
|
207
205
|
if (["range", "date", "time", "datetime"].includes(column.filter.type)) {
|
|
@@ -215,7 +213,6 @@ function applyFilters(entity, rows) {
|
|
|
215
213
|
return value === filterValue
|
|
216
214
|
}
|
|
217
215
|
|
|
218
|
-
// String filtering (case-insensitive contains)
|
|
219
216
|
return String(value)
|
|
220
217
|
.toLowerCase()
|
|
221
218
|
.includes(String(filterValue).toLowerCase())
|
|
@@ -262,7 +259,6 @@ function applySorts(entity, rows) {
|
|
|
262
259
|
let aVal = a[columnId]
|
|
263
260
|
let bVal = b[columnId]
|
|
264
261
|
|
|
265
|
-
// Custom sort function
|
|
266
262
|
if (column?.sortFn) {
|
|
267
263
|
const result =
|
|
268
264
|
direction === "asc" ? column.sortFn(a, b) : column.sortFn(b, a)
|
|
@@ -270,7 +266,6 @@ function applySorts(entity, rows) {
|
|
|
270
266
|
continue
|
|
271
267
|
}
|
|
272
268
|
|
|
273
|
-
// Default sorting
|
|
274
269
|
if (aVal === bVal) continue
|
|
275
270
|
if (aVal == null) return 1
|
|
276
271
|
if (bVal == null) return -1
|
|
@@ -264,7 +264,6 @@ export const DataGrid = {
|
|
|
264
264
|
const column = props.columns[index]
|
|
265
265
|
const isEditable = Boolean(column.isEditable && row)
|
|
266
266
|
|
|
267
|
-
// Typing in a cell's editor is not picking its row.
|
|
268
267
|
return html`<div
|
|
269
268
|
class="iw-data-grid-cell ${classMap({
|
|
270
269
|
"iw-data-grid-cell-number": column.type === "number",
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/* The size is a floor, not a fixed box. A glyph or an `icon` takes the size's
|
|
2
|
-
font-size and fits it exactly, an SVG being drawn at 1em; content that sizes
|
|
3
|
-
itself (an SVG with its own width, a button) grows the box instead of
|
|
4
|
-
overflowing it or being squeezed into it. */
|
|
5
1
|
.iw-icon {
|
|
6
2
|
display: inline-flex;
|
|
7
3
|
align-items: center;
|
|
@@ -26,9 +22,6 @@
|
|
|
26
22
|
font-size: var(--iw-font-size-2xl);
|
|
27
23
|
}
|
|
28
24
|
|
|
29
|
-
/* An icon that points along the line, in right-to-left text. `scale`
|
|
30
|
-
rather than `transform`, so it adds to a rotation set elsewhere instead
|
|
31
|
-
of replacing it. */
|
|
32
25
|
&.iw-icon-rtl {
|
|
33
26
|
scale: -1 1;
|
|
34
27
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @typedef {import('@inglorious/web').TemplateResult} TemplateResult
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { html } from "@inglorious/web"
|
|
7
|
+
import { html, nothing } from "@inglorious/web"
|
|
8
8
|
import { classMap } from "@inglorious/web/directives/class-map"
|
|
9
9
|
import { ref } from "@inglorious/web/directives/ref"
|
|
10
10
|
import { unsafeSVG } from "@inglorious/web/directives/unsafe-svg"
|
|
@@ -53,7 +53,7 @@ export function render({
|
|
|
53
53
|
"iw-icon-rtl": direction === "rtl",
|
|
54
54
|
...extraClasses,
|
|
55
55
|
})}
|
|
56
|
-
style=${color !== "current" ? `color: ${color};` :
|
|
56
|
+
style=${color !== "current" ? `color: ${color};` : nothing}
|
|
57
57
|
@click=${onClick}
|
|
58
58
|
${ref((el) =>
|
|
59
59
|
applyElementProps(el, {
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/* The bubble is anchored to the trigger by CSS: the browser places it on the
|
|
2
|
-
requested side and flips it to the opposite one when it would leave the
|
|
3
|
-
viewport. Fixed, so a container that clips its overflow does not cut it. */
|
|
4
1
|
.iw-tooltip {
|
|
5
2
|
anchor-scope: --iw-tooltip;
|
|
6
3
|
display: inline-flex;
|
|
@@ -45,8 +45,6 @@ export function scroll(entity, containerEl) {
|
|
|
45
45
|
*/
|
|
46
46
|
export function mount(entity, containerEl) {
|
|
47
47
|
const firstItem = containerEl.querySelector("[data-index]")
|
|
48
|
-
// A list not laid out yet, such as one rendered into a detached element,
|
|
49
|
-
// measures 0: keep the estimate, and measure again on a later render.
|
|
50
48
|
if (!firstItem?.offsetHeight) return
|
|
51
49
|
|
|
52
50
|
entity.itemHeight = firstItem.offsetHeight
|
|
@@ -4,15 +4,13 @@
|
|
|
4
4
|
* @typedef {import('@inglorious/web').Api} Api
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { html } from "@inglorious/web"
|
|
7
|
+
import { html, nothing } from "@inglorious/web"
|
|
8
8
|
import { ref } from "@inglorious/web/directives/ref"
|
|
9
9
|
import { repeat } from "@inglorious/web/directives/repeat"
|
|
10
10
|
import { styleMap } from "@inglorious/web/directives/style-map"
|
|
11
11
|
|
|
12
12
|
const PRETTY_INDEX = 1
|
|
13
13
|
|
|
14
|
-
// The list elements already being measured. Every update re-renders, and
|
|
15
|
-
// measuring is an update, so measuring on each render would loop forever.
|
|
16
14
|
const measured = new WeakSet()
|
|
17
15
|
|
|
18
16
|
/**
|
|
@@ -49,7 +47,7 @@ export function render(entity, api) {
|
|
|
49
47
|
|
|
50
48
|
return html`
|
|
51
49
|
<div
|
|
52
|
-
class=${className ??
|
|
50
|
+
class=${className ?? nothing}
|
|
53
51
|
style=${styleMap({ height: `${viewportHeight}px`, overflow: "auto" })}
|
|
54
52
|
@scroll=${(e) => api.notify(`#${entity.id}:scroll`, e.currentTarget)}
|
|
55
53
|
${ref((el) => {
|
|
@@ -9,9 +9,6 @@ export const beforeAfterImages = {
|
|
|
9
9
|
},
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
// Self-contained demo images for the Before/After control, so the dashboard
|
|
13
|
-
// renders the comparison without any network requests.
|
|
14
|
-
|
|
15
12
|
function svg(label, from, to) {
|
|
16
13
|
return (
|
|
17
14
|
"data:image/svg+xml," +
|
|
@@ -1525,8 +1525,6 @@ function toTitleCase(slug) {
|
|
|
1525
1525
|
function livePreview(types, entity) {
|
|
1526
1526
|
if (!livePreviews.has(entity.id)) {
|
|
1527
1527
|
const container = document.createElement("div")
|
|
1528
|
-
// The mount needs an element, but it must not become a box of its own:
|
|
1529
|
-
// as a flex item it would shrink and take the primitive down with it.
|
|
1530
1528
|
container.style.display = "contents"
|
|
1531
1529
|
|
|
1532
1530
|
const store = createStore({ types, entities: { [entity.id]: entity } })
|
|
@@ -57,7 +57,6 @@
|
|
|
57
57
|
width: 100%;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
/* Outside the app bar, so it pads itself to line up with it. */
|
|
61
60
|
.iw-dashboard-breadcrumbs {
|
|
62
61
|
min-height: var(--iw-space-12);
|
|
63
62
|
padding-inline: var(--iw-space-4);
|
|
@@ -261,8 +260,6 @@
|
|
|
261
260
|
inset: 0;
|
|
262
261
|
}
|
|
263
262
|
|
|
264
|
-
/* Shown in place (isModal: false), so it can sit in the preview's flow
|
|
265
|
-
rather than where the browser positions a non-modal dialog. */
|
|
266
263
|
.iw-primitive-preview .iw-dialog {
|
|
267
264
|
position: static;
|
|
268
265
|
min-width: 0;
|
|
@@ -10,14 +10,15 @@ export default {
|
|
|
10
10
|
argTypes: {
|
|
11
11
|
isOpen: { control: "boolean" },
|
|
12
12
|
isModal: { control: "boolean" },
|
|
13
|
+
variant: { control: "select", options: ["dialog", "sheet"] },
|
|
13
14
|
size: { control: "select", options: ["sm", "md", "lg"] },
|
|
14
15
|
title: { control: "text" },
|
|
15
16
|
description: { control: "text" },
|
|
17
|
+
closeLabel: { control: "text" },
|
|
16
18
|
onClose: { action: "onClose" },
|
|
17
19
|
},
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
// In place, so the docs page that shows every story stays usable.
|
|
21
22
|
export const Open = {
|
|
22
23
|
args: {
|
|
23
24
|
isOpen: true,
|
|
@@ -51,8 +52,12 @@ export const Large = {
|
|
|
51
52
|
},
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
// Modal takes over the page, so it is left out of the docs page.
|
|
55
55
|
export const Modal = {
|
|
56
56
|
tags: ["!autodocs"],
|
|
57
57
|
args: { ...Open.args, isModal: true },
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
export const Sheet = {
|
|
61
|
+
tags: ["!autodocs"],
|
|
62
|
+
args: { ...Open.args, isModal: true, variant: "sheet" },
|
|
63
|
+
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/* A native <dialog>, so the browser's own box is reset: the surface inside
|
|
2
|
-
carries the padding, which leaves the dialog element itself reachable only
|
|
3
|
-
through the backdrop. Modal dialogs sit in the top layer, above any
|
|
4
|
-
z-index, and the browser centres them. */
|
|
5
1
|
.iw-dialog {
|
|
6
2
|
background: var(--iw-color-surface);
|
|
7
3
|
color: var(--iw-color-text);
|
|
@@ -48,20 +44,7 @@
|
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
.iw-dialog-close {
|
|
51
|
-
|
|
52
|
-
background: transparent;
|
|
53
|
-
width: 1.75rem;
|
|
54
|
-
height: 1.75rem;
|
|
55
|
-
border-radius: var(--iw-radius-sm);
|
|
56
|
-
display: inline-flex;
|
|
57
|
-
align-items: center;
|
|
58
|
-
justify-content: center;
|
|
59
|
-
cursor: pointer;
|
|
60
|
-
color: inherit;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.iw-dialog-close:hover {
|
|
64
|
-
background-color: color-mix(in srgb, currentColor 12%, transparent);
|
|
47
|
+
flex-shrink: 0;
|
|
65
48
|
}
|
|
66
49
|
|
|
67
50
|
.iw-dialog-description {
|
|
@@ -80,3 +63,33 @@
|
|
|
80
63
|
flex-wrap: wrap;
|
|
81
64
|
gap: var(--iw-space-2);
|
|
82
65
|
}
|
|
66
|
+
|
|
67
|
+
@media (width < 48rem) {
|
|
68
|
+
dialog.iw-dialog.iw-dialog-sheet {
|
|
69
|
+
inset: auto 0 0;
|
|
70
|
+
margin: 0;
|
|
71
|
+
width: 100%;
|
|
72
|
+
min-width: 0;
|
|
73
|
+
max-width: 100%;
|
|
74
|
+
max-height: 85dvh;
|
|
75
|
+
padding-bottom: var(--safe-area-bottom, 0px);
|
|
76
|
+
border-end-start-radius: 0;
|
|
77
|
+
border-end-end-radius: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
dialog.iw-dialog.iw-dialog-sheet[open] {
|
|
81
|
+
animation: iw-dialog-sheet-in 0.32s cubic-bezier(0.22, 1, 0.36, 1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@keyframes iw-dialog-sheet-in {
|
|
86
|
+
from {
|
|
87
|
+
transform: translateY(100%);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@media (prefers-reduced-motion: reduce) {
|
|
92
|
+
dialog.iw-dialog.iw-dialog-sheet[open] {
|
|
93
|
+
animation: none;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -8,6 +8,9 @@ import { classMap } from "@inglorious/web/directives/class-map"
|
|
|
8
8
|
import { ref } from "@inglorious/web/directives/ref"
|
|
9
9
|
import { when } from "@inglorious/web/directives/when"
|
|
10
10
|
|
|
11
|
+
import { IconButton } from "../../controls/icon-button/index.js"
|
|
12
|
+
import { Icon } from "../../data-display/icon/index.js"
|
|
13
|
+
import { close } from "../../shared/icons.js"
|
|
11
14
|
import { syncDialog } from "../../shared/top-layer.js"
|
|
12
15
|
|
|
13
16
|
/**
|
|
@@ -29,12 +32,14 @@ export function render(props) {
|
|
|
29
32
|
id,
|
|
30
33
|
isOpen = false,
|
|
31
34
|
isModal = true,
|
|
35
|
+
variant = "dialog",
|
|
32
36
|
size = "md",
|
|
33
37
|
title,
|
|
34
38
|
description,
|
|
35
39
|
children,
|
|
36
40
|
actions,
|
|
37
41
|
className = "",
|
|
42
|
+
closeLabel = "Close",
|
|
38
43
|
onClose,
|
|
39
44
|
onBackdropClick,
|
|
40
45
|
} = props
|
|
@@ -50,15 +55,12 @@ export function render(props) {
|
|
|
50
55
|
const descriptionId = id && description ? `${id}-description` : ""
|
|
51
56
|
const onBackdrop = onBackdropClick ?? onClose
|
|
52
57
|
|
|
53
|
-
// The surface fills the dialog box, so a click that lands on the dialog
|
|
54
|
-
// itself can only have come from the backdrop around it. The press has to
|
|
55
|
-
// start there too: a drag from inside the surface that ends on the backdrop
|
|
56
|
-
// also clicks the dialog, and must not close it.
|
|
57
58
|
return html`<dialog
|
|
58
59
|
id=${id || nothing}
|
|
59
60
|
class=${classMap({
|
|
60
61
|
"iw-dialog": true,
|
|
61
62
|
[`iw-dialog-${size}`]: true,
|
|
63
|
+
"iw-dialog-sheet": variant === "sheet",
|
|
62
64
|
...extraClasses,
|
|
63
65
|
})}
|
|
64
66
|
aria-labelledby=${titleId || nothing}
|
|
@@ -77,7 +79,6 @@ export function render(props) {
|
|
|
77
79
|
}
|
|
78
80
|
}}
|
|
79
81
|
@cancel=${(event) => {
|
|
80
|
-
// Without onClose nothing would take isOpen down, so Esc is refused.
|
|
81
82
|
if (!onClose) event.preventDefault()
|
|
82
83
|
}}
|
|
83
84
|
${ref((element) => syncDialog(element, { isOpen, isModal, onClose }))}
|
|
@@ -94,17 +95,16 @@ export function render(props) {
|
|
|
94
95
|
${title}
|
|
95
96
|
</div>`,
|
|
96
97
|
)}
|
|
97
|
-
${when(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
</button>`,
|
|
98
|
+
${when(onClose, () =>
|
|
99
|
+
IconButton.render({
|
|
100
|
+
icon: Icon.render({ icon: close, size: "lg" }),
|
|
101
|
+
ariaLabel: closeLabel,
|
|
102
|
+
variant: "ghost",
|
|
103
|
+
color: "secondary",
|
|
104
|
+
shape: "round",
|
|
105
|
+
className: "iw-dialog-close",
|
|
106
|
+
onClick: onClose,
|
|
107
|
+
}),
|
|
108
108
|
)}
|
|
109
109
|
</div>`,
|
|
110
110
|
)}
|
|
@@ -24,10 +24,6 @@
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
/* A native <progress>, restyled. Browsers draw its value through their own
|
|
28
|
-
pseudo-elements, so the look is set once here: the bar takes `color`, like
|
|
29
|
-
the color variants above, and an app adjusts the rest through
|
|
30
|
-
--iw-progress-height, --iw-progress-radius and --iw-progress-track-color. */
|
|
31
27
|
.iw-progress-linear {
|
|
32
28
|
--iw-progress-bar: linear-gradient(
|
|
33
29
|
90deg,
|
|
@@ -63,8 +59,6 @@
|
|
|
63
59
|
border-radius: var(--iw-progress-radius, var(--iw-radius-sm));
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
/* Indeterminate: no value to draw, so a sliver of the bar sweeps across
|
|
67
|
-
the track, painted on the element itself. */
|
|
68
62
|
&:indeterminate {
|
|
69
63
|
background:
|
|
70
64
|
var(--iw-progress-bar) no-repeat 0 0 / 30% 100%,
|
|
@@ -77,9 +77,6 @@ export function render(props) {
|
|
|
77
77
|
|
|
78
78
|
const progress = value == null ? null : clamp(value)
|
|
79
79
|
|
|
80
|
-
// An attribute, not a property: removing it is the only way back to
|
|
81
|
-
// indeterminate, which `:indeterminate` styles and assistive tech announces
|
|
82
|
-
// as busy.
|
|
83
80
|
return html`<progress
|
|
84
81
|
class=${classMap({
|
|
85
82
|
"iw-progress": true,
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/* Fixed to the viewport, clear of the system bars. A bottom snackbar also
|
|
2
|
-
clears whatever bar the app keeps at the bottom: the app sets
|
|
3
|
-
--iw-snackbar-offset-bottom to that bar's height while it shows, and the
|
|
4
|
-
offset then stands in for the safe area, which the bar already covers.
|
|
5
|
-
Only the app knows when its bar is on screen, so nothing is guessed here. */
|
|
6
1
|
.iw-snackbar {
|
|
7
2
|
--iw-snackbar-gap: var(--iw-space-4);
|
|
8
3
|
position: fixed;
|
|
@@ -10,9 +5,6 @@
|
|
|
10
5
|
max-width: calc(100vw - 2 * var(--iw-snackbar-gap));
|
|
11
6
|
}
|
|
12
7
|
|
|
13
|
-
/* A manual popover in the top layer. The browser centres a popover in the
|
|
14
|
-
viewport as a bordered box, so its insets and box are reset, with no
|
|
15
|
-
specificity so the positions below still set their own sides. */
|
|
16
8
|
:where(.iw-snackbar) {
|
|
17
9
|
inset: auto;
|
|
18
10
|
margin: 0;
|
|
@@ -48,8 +40,6 @@
|
|
|
48
40
|
right: var(--iw-snackbar-gap);
|
|
49
41
|
}
|
|
50
42
|
|
|
51
|
-
/* Both insets and auto margins: the snackbar is as wide as its content, up
|
|
52
|
-
to the gutters, and centered within them. */
|
|
53
43
|
.iw-snackbar-bottom-center,
|
|
54
44
|
.iw-snackbar-top-center {
|
|
55
45
|
inset-inline: var(--iw-snackbar-gap);
|
|
@@ -129,8 +129,6 @@
|
|
|
129
129
|
padding: var(--iw-space-8);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
/* A flex item needs both minimum dimensions released before either axis can
|
|
133
|
-
overflow instead of expanding its parent. */
|
|
134
132
|
&.iw-flex-overflow-auto,
|
|
135
133
|
&.iw-flex-overflow-scroll,
|
|
136
134
|
&.iw-flex-overflow-hidden,
|
|
@@ -19,8 +19,6 @@
|
|
|
19
19
|
align-items: center;
|
|
20
20
|
justify-content: center;
|
|
21
21
|
gap: var(--iw-space-1);
|
|
22
|
-
/* Narrow sides: a tab is a quarter or a fifth of a phone, and its label
|
|
23
|
-
needs every pixel of it. */
|
|
24
22
|
padding: var(--iw-space-2) var(--iw-space-1);
|
|
25
23
|
cursor: pointer;
|
|
26
24
|
}
|
|
@@ -29,13 +27,8 @@
|
|
|
29
27
|
color: var(--iw-color-primary);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
/* 12px, as Material sizes navigation labels: at 14px, "Applications" or
|
|
33
|
-
"Candidatures" does not fit a quarter of a 360px phone. */
|
|
34
30
|
.iw-bottom-navigation-label {
|
|
35
31
|
font-size: var(--iw-font-size-xs);
|
|
36
|
-
/* One line, like its neighbours: a label too long for its tab is cut short
|
|
37
|
-
rather than wrapping, which in languages that break between any two
|
|
38
|
-
characters (Japanese, Chinese) splits a word and makes the bar taller. */
|
|
39
32
|
max-width: 100%;
|
|
40
33
|
overflow: hidden;
|
|
41
34
|
text-overflow: ellipsis;
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/* While it overlays the page the drawer is a popover in the top layer. The
|
|
2
|
-
browser styles every popover as a centred, bordered box hidden until it
|
|
3
|
-
opens, so those defaults are reset here: the drawer stays displayed while
|
|
4
|
-
closed, off-screen or docked, and slides rather than appears. */
|
|
5
1
|
.iw-drawer {
|
|
6
2
|
display: flex;
|
|
7
3
|
flex-direction: column;
|
|
@@ -24,8 +20,6 @@
|
|
|
24
20
|
inset-block: 0;
|
|
25
21
|
z-index: var(--iw-z-modal, 1050);
|
|
26
22
|
|
|
27
|
-
/* As tall as an app bar, so the line under a drawer and the app bar beside
|
|
28
|
-
it runs straight across. */
|
|
29
23
|
.iw-drawer-header {
|
|
30
24
|
min-height: var(--iw-space-16);
|
|
31
25
|
border-bottom: 1px solid var(--iw-color-border);
|
|
@@ -52,8 +46,6 @@
|
|
|
52
46
|
transition: transform var(--iw-transition-fast);
|
|
53
47
|
}
|
|
54
48
|
|
|
55
|
-
/* The toggle points at the edge the drawer sits on, which a right-to-left
|
|
56
|
-
page mirrors. `scale`, so the collapsed state's rotation still applies. */
|
|
57
49
|
.iw-drawer-toggler > span:dir(rtl) {
|
|
58
50
|
scale: -1 1;
|
|
59
51
|
}
|
|
@@ -84,15 +76,10 @@
|
|
|
84
76
|
opacity: 0;
|
|
85
77
|
}
|
|
86
78
|
|
|
87
|
-
/* The header keeps only what fits the rail, such as a brand mark, so
|
|
88
|
-
it centres it. */
|
|
89
79
|
.iw-drawer-header {
|
|
90
80
|
justify-content: center;
|
|
91
81
|
}
|
|
92
82
|
|
|
93
|
-
/* Only the icon is left, centred in the rail. The label also has to
|
|
94
|
-
leave the row: faded out, it still took its width and pushed the
|
|
95
|
-
icon off centre, as did the icon's side margin. */
|
|
96
83
|
.iw-list-item > .iw-flex {
|
|
97
84
|
justify-content: center;
|
|
98
85
|
}
|
|
@@ -112,8 +99,6 @@
|
|
|
112
99
|
}
|
|
113
100
|
}
|
|
114
101
|
|
|
115
|
-
/* `left` and `right` are the start and end of the line: the left drawer
|
|
116
|
-
sits on the right in a right-to-left page, and slides off that way. */
|
|
117
102
|
.iw-drawer-left {
|
|
118
103
|
inset-inline: 0 auto;
|
|
119
104
|
border-inline-end: 1px solid var(--iw-color-border);
|
|
@@ -136,9 +121,6 @@
|
|
|
136
121
|
backdrop-filter: none;
|
|
137
122
|
}
|
|
138
123
|
|
|
139
|
-
/* Overlaying: a temporary drawer at every width, a responsive one below
|
|
140
|
-
64rem. Off-screen until open, raised, closed from its header. The collapse
|
|
141
|
-
toggle only makes sense for a rail, so the footer goes. */
|
|
142
124
|
.iw-drawer {
|
|
143
125
|
box-shadow: var(--iw-shadow-lg);
|
|
144
126
|
|
|
@@ -151,9 +133,6 @@
|
|
|
151
133
|
}
|
|
152
134
|
}
|
|
153
135
|
|
|
154
|
-
/* Docked: a permanent drawer at every width, a responsive one from 64rem
|
|
155
|
-
(keep in step with DOCKED_QUERY in template.js). In place, flat, and
|
|
156
|
-
hidden only on request. */
|
|
157
136
|
.iw-drawer-permanent {
|
|
158
137
|
transform: none;
|
|
159
138
|
box-shadow: none;
|