@inglorious/ui 8.6.0 → 9.1.0
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 +2 -2
- package/src/controls/button/button.stories.js +7 -1
- package/src/controls/button/style.css +11 -0
- package/src/controls/button/template.js +4 -4
- package/src/controls/checkbox/checkbox.stories.js +12 -0
- package/src/controls/checkbox/style.css +11 -0
- package/src/controls/checkbox/template.js +9 -1
- package/src/controls/combobox/style.css +14 -7
- package/src/controls/combobox/template.js +12 -2
- package/src/controls/radio-group/radio-group.stories.js +21 -1
- package/src/controls/radio-group/style.css +11 -0
- package/src/controls/radio-group/template.js +11 -1
- package/src/controls/rating/rating.stories.js +8 -0
- package/src/controls/rating/style.css +26 -4
- package/src/controls/rating/template.js +29 -12
- package/src/controls/slider/slider.stories.js +28 -1
- package/src/controls/slider/style.css +102 -0
- package/src/controls/slider/template.js +114 -15
- package/src/controls/switch/style.css +11 -0
- package/src/controls/switch/switch.stories.js +10 -0
- package/src/controls/switch/template.js +14 -2
- package/src/data-display/chip/chip.stories.js +17 -0
- package/src/data-display/chip/style.css +5 -0
- package/src/data-display/chip/template.js +3 -1
- package/src/data-display/divider/divider.stories.js +9 -0
- package/src/data-display/divider/template.js +12 -4
- package/src/data-display/tooltip/style.css +22 -14
- package/src/examples/dashboard/primitive-content.js +6 -6
- package/src/examples/dashboard/style.css +11 -5
- package/src/feedback/alert/alert.stories.js +9 -1
- package/src/feedback/alert/style.css +5 -0
- package/src/feedback/alert/template.js +2 -1
- package/src/feedback/dialog/dialog.stories.js +31 -0
- package/src/feedback/dialog/style.css +27 -13
- package/src/feedback/dialog/template.js +68 -18
- package/src/feedback/progress/progress.stories.js +5 -0
- package/src/feedback/progress/style.css +47 -23
- package/src/feedback/progress/template.js +18 -11
- package/src/feedback/snackbar/style.css +13 -0
- package/src/feedback/snackbar/template.js +7 -0
- package/src/layout/flex/flex.stories.js +1 -1
- package/src/layout/flex/style.css +8 -0
- package/src/navigation/drawer/drawer.stories.js +3 -7
- package/src/navigation/drawer/style.css +59 -18
- package/src/navigation/drawer/template.js +137 -80
- package/src/navigation/menu/menu.stories.js +15 -0
- package/src/navigation/menu/style.css +19 -0
- package/src/navigation/menu/template.js +59 -6
- package/src/navigation/speed-dial/style.css +32 -5
- package/src/navigation/speed-dial/template.js +41 -12
- package/src/navigation/tabs/template.js +52 -4
- package/src/shared/anchor.js +11 -0
- package/src/shared/top-layer.js +83 -0
- package/src/surfaces/accordion/accordion.stories.js +9 -0
- package/src/surfaces/accordion/style.css +14 -7
- package/src/surfaces/accordion/template.js +31 -20
- package/src/surfaces/card/card.stories.js +24 -0
- package/src/surfaces/card/style.css +15 -0
- package/src/surfaces/card/template.js +2 -0
- package/types/controls/button.d.ts +1 -1
- package/types/controls/checkbox.d.ts +2 -0
- package/types/controls/radio-group.d.ts +2 -0
- package/types/controls/rating.d.ts +4 -0
- package/types/controls/slider.d.ts +6 -2
- package/types/controls/switch.d.ts +2 -0
- package/types/data-display/chip.d.ts +2 -0
- package/types/data-display/divider.d.ts +2 -0
- package/types/feedback/alert.d.ts +1 -1
- package/types/feedback/dialog.d.ts +5 -1
- package/types/feedback/progress.d.ts +2 -0
- package/types/layout/flex.d.ts +1 -1
- package/types/navigation/drawer.d.ts +8 -3
- package/types/navigation/menu.d.ts +17 -0
- package/types/navigation/speed-dial.d.ts +5 -0
- package/types/surfaces/accordion.d.ts +2 -0
- package/types/surfaces/card.d.ts +5 -0
|
@@ -14,10 +14,17 @@ const DEFAULT_VALUE = 0
|
|
|
14
14
|
const DEFAULT_MIN = 0
|
|
15
15
|
const DEFAULT_MAX = 100
|
|
16
16
|
const DEFAULT_STEP = 1
|
|
17
|
+
const PERCENT = 100
|
|
18
|
+
/** Past this many steps, marks would be a smear rather than a scale. */
|
|
19
|
+
const MAX_MARKS = 100
|
|
20
|
+
const RANGE_LENGTH = 2
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* Renders a range slider with optional label and current value display.
|
|
20
24
|
* Supports min/max/step, color, disabled state, and full-width layout.
|
|
25
|
+
* With a `[low, high]` value it has two thumbs, one for each end of a range:
|
|
26
|
+
* two native range inputs on one track, so each keeps the keyboard and
|
|
27
|
+
* assistive tech support of the platform. `hasMarks` draws a tick per step.
|
|
21
28
|
* @param {SliderProps} props
|
|
22
29
|
* @returns {TemplateResult}
|
|
23
30
|
*/
|
|
@@ -35,14 +42,18 @@ export function render(props) {
|
|
|
35
42
|
color = "primary",
|
|
36
43
|
isValueVisible = true,
|
|
37
44
|
isFullWidth = false,
|
|
45
|
+
hasMarks = false,
|
|
38
46
|
onChange,
|
|
39
47
|
...rest
|
|
40
48
|
} = props
|
|
41
49
|
|
|
42
50
|
const inputId = id || name
|
|
51
|
+
const isRange = Array.isArray(value) && value.length === RANGE_LENGTH
|
|
52
|
+
const shown = isRange ? `${value[0]} – ${value[1]}` : value
|
|
43
53
|
|
|
44
54
|
const classes = {
|
|
45
55
|
"iw-slider": true,
|
|
56
|
+
"iw-slider-range": isRange,
|
|
46
57
|
[`iw-slider-${color}`]: color !== "primary",
|
|
47
58
|
"iw-slider-full-width": isFullWidth,
|
|
48
59
|
}
|
|
@@ -59,25 +70,113 @@ export function render(props) {
|
|
|
59
70
|
}
|
|
60
71
|
${
|
|
61
72
|
isValueVisible
|
|
62
|
-
? html`<output class="iw-slider-value">${
|
|
73
|
+
? html`<output class="iw-slider-value">${shown}</output>`
|
|
63
74
|
: null
|
|
64
75
|
}
|
|
65
76
|
</div>`
|
|
66
77
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
${
|
|
79
|
+
isRange
|
|
80
|
+
? renderRange({
|
|
81
|
+
inputId,
|
|
82
|
+
name,
|
|
83
|
+
label,
|
|
84
|
+
value,
|
|
85
|
+
min,
|
|
86
|
+
max,
|
|
87
|
+
step,
|
|
88
|
+
isDisabled,
|
|
89
|
+
onChange,
|
|
90
|
+
rest,
|
|
91
|
+
})
|
|
92
|
+
: html`<input
|
|
93
|
+
id=${inputId || nothing}
|
|
94
|
+
class="iw-slider-input"
|
|
95
|
+
aria-label=${fallbackLabel(inputId, label)}
|
|
96
|
+
type="range"
|
|
97
|
+
name=${name}
|
|
98
|
+
min=${min}
|
|
99
|
+
max=${max}
|
|
100
|
+
step=${step}
|
|
101
|
+
.value=${String(value)}
|
|
102
|
+
?disabled=${isDisabled}
|
|
103
|
+
@input=${(event) => onChange?.(Number(event.target.value))}
|
|
104
|
+
${ref((element) => applyElementProps(element, rest))}
|
|
105
|
+
/>`
|
|
106
|
+
}
|
|
107
|
+
${hasMarks ? renderMarks({ min, max, step }) : nothing}
|
|
81
108
|
</div>
|
|
82
109
|
`
|
|
83
110
|
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Two thumbs on one track. Each input stops at the other's value, so the
|
|
114
|
+
* range never turns inside out, and the track is filled between them.
|
|
115
|
+
*/
|
|
116
|
+
function renderRange({
|
|
117
|
+
inputId,
|
|
118
|
+
name,
|
|
119
|
+
label,
|
|
120
|
+
value,
|
|
121
|
+
min,
|
|
122
|
+
max,
|
|
123
|
+
step,
|
|
124
|
+
isDisabled,
|
|
125
|
+
onChange,
|
|
126
|
+
rest,
|
|
127
|
+
}) {
|
|
128
|
+
const [low, high] = value
|
|
129
|
+
const span = max - min || DEFAULT_STEP
|
|
130
|
+
const fill = `--iw-slider-low: ${((low - min) / span) * PERCENT}%; --iw-slider-high: ${((high - min) / span) * PERCENT}%`
|
|
131
|
+
const endName = (end) => (name ? `${name}-${end}` : nothing)
|
|
132
|
+
// Each thumb is named for its end of the range, after the slider's label.
|
|
133
|
+
const endLabel = (end) =>
|
|
134
|
+
typeof label === "string" && label ? `${label} ${end}` : end
|
|
135
|
+
|
|
136
|
+
return html`<div class="iw-slider-track" style=${fill}>
|
|
137
|
+
<input
|
|
138
|
+
id=${inputId || nothing}
|
|
139
|
+
class="iw-slider-input"
|
|
140
|
+
aria-label=${endLabel("minimum")}
|
|
141
|
+
type="range"
|
|
142
|
+
name=${endName("min")}
|
|
143
|
+
min=${min}
|
|
144
|
+
max=${max}
|
|
145
|
+
step=${step}
|
|
146
|
+
.value=${String(low)}
|
|
147
|
+
?disabled=${isDisabled}
|
|
148
|
+
@input=${(event) => {
|
|
149
|
+
const next = Math.min(Number(event.target.value), high)
|
|
150
|
+
event.target.value = String(next)
|
|
151
|
+
onChange?.([next, high])
|
|
152
|
+
}}
|
|
153
|
+
${ref((element) => applyElementProps(element, rest))}
|
|
154
|
+
/>
|
|
155
|
+
<input
|
|
156
|
+
class="iw-slider-input"
|
|
157
|
+
aria-label=${endLabel("maximum")}
|
|
158
|
+
type="range"
|
|
159
|
+
name=${endName("max")}
|
|
160
|
+
min=${min}
|
|
161
|
+
max=${max}
|
|
162
|
+
step=${step}
|
|
163
|
+
.value=${String(high)}
|
|
164
|
+
?disabled=${isDisabled}
|
|
165
|
+
@input=${(event) => {
|
|
166
|
+
const next = Math.max(Number(event.target.value), low)
|
|
167
|
+
event.target.value = String(next)
|
|
168
|
+
onChange?.([low, next])
|
|
169
|
+
}}
|
|
170
|
+
/>
|
|
171
|
+
</div>`
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** A tick per step, spread along the track. Decorative. */
|
|
175
|
+
function renderMarks({ min, max, step }) {
|
|
176
|
+
const count = Math.floor((max - min) / step) + 1
|
|
177
|
+
if (!(count > 1) || count > MAX_MARKS) return nothing
|
|
178
|
+
|
|
179
|
+
return html`<div class="iw-slider-marks" aria-hidden="true">
|
|
180
|
+
${Array.from({ length: count }, () => html`<span></span>`)}
|
|
181
|
+
</div>`
|
|
182
|
+
}
|
|
@@ -43,6 +43,17 @@
|
|
|
43
43
|
transform: translateX(calc(1rem * var(--iw-dir-sign, 1)));
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/* With a description, the label and it stack beside the track. */
|
|
47
|
+
.iw-switch-text {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.iw-switch-description {
|
|
53
|
+
font-size: var(--iw-font-size-sm);
|
|
54
|
+
color: var(--iw-color-text-secondary);
|
|
55
|
+
}
|
|
56
|
+
|
|
46
57
|
.iw-switch-label {
|
|
47
58
|
color: var(--iw-color-text);
|
|
48
59
|
font-size: var(--iw-font-size-base);
|
|
@@ -7,6 +7,10 @@ export default {
|
|
|
7
7
|
render: createRender(Switch),
|
|
8
8
|
argTypes: {
|
|
9
9
|
label: { control: "text", description: "Label text." },
|
|
10
|
+
description: {
|
|
11
|
+
control: "text",
|
|
12
|
+
description: "A line of detail under the label.",
|
|
13
|
+
},
|
|
10
14
|
name: { control: "text", description: "Native input name." },
|
|
11
15
|
isChecked: { control: "boolean", description: "Current checked state." },
|
|
12
16
|
isDisabled: { control: "boolean", description: "Disables interaction." },
|
|
@@ -46,3 +50,9 @@ On.args = {
|
|
|
46
50
|
...Default.args,
|
|
47
51
|
isChecked: true,
|
|
48
52
|
}
|
|
53
|
+
|
|
54
|
+
export const WithDescription = {}
|
|
55
|
+
WithDescription.args = {
|
|
56
|
+
...Default.args,
|
|
57
|
+
description: "Alerts when a payment is due or a budget runs out.",
|
|
58
|
+
}
|
|
@@ -10,7 +10,8 @@ import { ref } from "@inglorious/web/directives/ref"
|
|
|
10
10
|
import { applyElementProps } from "../../shared/apply-element-props.js"
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Renders a toggle switch backed by a checkbox input
|
|
13
|
+
* Renders a toggle switch backed by a checkbox input, which `role="switch"`
|
|
14
|
+
* has assistive tech announce as on/off rather than checked.
|
|
14
15
|
* Use it for boolean settings with optional labels and disabled state.
|
|
15
16
|
* @param {SwitchProps} props
|
|
16
17
|
* @returns {TemplateResult}
|
|
@@ -21,6 +22,7 @@ export function render(props) {
|
|
|
21
22
|
type, // eslint-disable-line no-unused-vars
|
|
22
23
|
name = "",
|
|
23
24
|
label = "",
|
|
25
|
+
description,
|
|
24
26
|
isChecked = false,
|
|
25
27
|
isDisabled = false,
|
|
26
28
|
color = "primary",
|
|
@@ -46,6 +48,7 @@ export function render(props) {
|
|
|
46
48
|
id=${inputId || nothing}
|
|
47
49
|
class="iw-switch-input"
|
|
48
50
|
type="checkbox"
|
|
51
|
+
role="switch"
|
|
49
52
|
name=${name}
|
|
50
53
|
.checked=${isChecked}
|
|
51
54
|
?disabled=${isDisabled}
|
|
@@ -55,7 +58,16 @@ export function render(props) {
|
|
|
55
58
|
<span class="iw-switch-track" aria-hidden="true">
|
|
56
59
|
<span class="iw-switch-thumb"></span>
|
|
57
60
|
</span>
|
|
58
|
-
${
|
|
61
|
+
${
|
|
62
|
+
description
|
|
63
|
+
? html`<span class="iw-switch-text">
|
|
64
|
+
${label ? html`<span class="iw-switch-label">${label}</span>` : null}
|
|
65
|
+
<span class="iw-switch-description">${description}</span>
|
|
66
|
+
</span>`
|
|
67
|
+
: label
|
|
68
|
+
? html`<span class="iw-switch-label">${label}</span>`
|
|
69
|
+
: null
|
|
70
|
+
}
|
|
59
71
|
</label>
|
|
60
72
|
`
|
|
61
73
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import sell from "@iconify-icons/material-symbols/sell"
|
|
2
|
+
|
|
1
3
|
import { createRender } from "../../stories/notify-story.js"
|
|
4
|
+
import { Icon } from "../icon"
|
|
2
5
|
import { Chip } from "."
|
|
3
6
|
|
|
4
7
|
export default {
|
|
@@ -7,6 +10,10 @@ export default {
|
|
|
7
10
|
render: createRender(Chip),
|
|
8
11
|
argTypes: {
|
|
9
12
|
children: { control: "text", description: "Chip label content." },
|
|
13
|
+
icon: {
|
|
14
|
+
control: false,
|
|
15
|
+
description: "Shown before the label, such as an `Icon.render(...)`.",
|
|
16
|
+
},
|
|
10
17
|
isRemovable: {
|
|
11
18
|
control: "boolean",
|
|
12
19
|
description: "Shows a remove affordance and emits `#id:remove`.",
|
|
@@ -55,3 +62,13 @@ export const Default = {
|
|
|
55
62
|
shape: "pill",
|
|
56
63
|
},
|
|
57
64
|
}
|
|
65
|
+
|
|
66
|
+
export const WithIcon = {
|
|
67
|
+
args: {
|
|
68
|
+
...Default.args,
|
|
69
|
+
children: "Paid",
|
|
70
|
+
icon: Icon.render({ icon: sell, size: "sm" }),
|
|
71
|
+
isRemovable: false,
|
|
72
|
+
color: "success",
|
|
73
|
+
},
|
|
74
|
+
}
|
|
@@ -7,7 +7,7 @@ import { html } from "@inglorious/web"
|
|
|
7
7
|
import { classMap } from "@inglorious/web/directives/class-map"
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Renders a compact chip label with optional remove action.
|
|
10
|
+
* Renders a compact chip label with an optional leading icon and remove action.
|
|
11
11
|
* Use chips for tags, filters, or selected values.
|
|
12
12
|
* @param {ChipProps} props
|
|
13
13
|
* @returns {TemplateResult}
|
|
@@ -15,6 +15,7 @@ import { classMap } from "@inglorious/web/directives/class-map"
|
|
|
15
15
|
export function render(props) {
|
|
16
16
|
const {
|
|
17
17
|
children,
|
|
18
|
+
icon,
|
|
18
19
|
isRemovable = false,
|
|
19
20
|
color = "default",
|
|
20
21
|
size = "md",
|
|
@@ -30,6 +31,7 @@ export function render(props) {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
return html`<span class=${classMap(classes)}>
|
|
34
|
+
${icon ? html`<span class="iw-chip-icon" aria-hidden="true">${icon}</span>` : null}
|
|
33
35
|
<span class="iw-chip-label">${children}</span>
|
|
34
36
|
${
|
|
35
37
|
isRemovable
|
|
@@ -17,6 +17,11 @@ export default {
|
|
|
17
17
|
control: "boolean",
|
|
18
18
|
description: "Applies start inset for sectional separators.",
|
|
19
19
|
},
|
|
20
|
+
isDecorative: {
|
|
21
|
+
control: "boolean",
|
|
22
|
+
description:
|
|
23
|
+
"Only visual: hidden from assistive tech, which otherwise announces a separator.",
|
|
24
|
+
},
|
|
20
25
|
},
|
|
21
26
|
parameters: {
|
|
22
27
|
docs: {
|
|
@@ -31,6 +36,10 @@ export const Default = {
|
|
|
31
36
|
args: {},
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
export const Decorative = {
|
|
40
|
+
args: { isDecorative: true },
|
|
41
|
+
}
|
|
42
|
+
|
|
34
43
|
export const Vertical = {
|
|
35
44
|
args: {
|
|
36
45
|
...Default.args,
|
|
@@ -3,23 +3,31 @@
|
|
|
3
3
|
* @typedef {import('@inglorious/web').TemplateResult} TemplateResult
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { html } from "@inglorious/web"
|
|
6
|
+
import { html, nothing } from "@inglorious/web"
|
|
7
7
|
import { classMap } from "@inglorious/web/directives/class-map"
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Renders a horizontal or vertical divider line
|
|
10
|
+
* Renders a horizontal or vertical divider line: a native `<hr>`, which
|
|
11
|
+
* assistive tech announces as a separator, unless it is only decorative.
|
|
11
12
|
* Supports inset styling for aligned content blocks.
|
|
12
13
|
* @param {DividerProps} props
|
|
13
14
|
* @returns {TemplateResult}
|
|
14
15
|
*/
|
|
15
16
|
export function render(props) {
|
|
16
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
orientation = "horizontal",
|
|
19
|
+
isInset = false,
|
|
20
|
+
isDecorative = false,
|
|
21
|
+
} = props
|
|
22
|
+
const isVertical = orientation === "vertical"
|
|
17
23
|
|
|
18
24
|
return html`<hr
|
|
19
25
|
class=${classMap({
|
|
20
26
|
"iw-divider": true,
|
|
21
|
-
"iw-divider-vertical":
|
|
27
|
+
"iw-divider-vertical": isVertical,
|
|
22
28
|
"iw-divider-inset": isInset,
|
|
23
29
|
})}
|
|
30
|
+
role=${isDecorative ? "none" : nothing}
|
|
31
|
+
aria-orientation=${isVertical && !isDecorative ? "vertical" : nothing}
|
|
24
32
|
/>`
|
|
25
33
|
}
|
|
@@ -1,10 +1,22 @@
|
|
|
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. */
|
|
1
4
|
.iw-tooltip {
|
|
2
|
-
|
|
5
|
+
anchor-scope: --iw-tooltip;
|
|
3
6
|
display: inline-flex;
|
|
4
7
|
align-items: center;
|
|
5
8
|
|
|
9
|
+
.iw-tooltip-trigger {
|
|
10
|
+
anchor-name: --iw-tooltip;
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
.iw-tooltip-bubble {
|
|
7
|
-
position:
|
|
14
|
+
position: fixed;
|
|
15
|
+
position-anchor: --iw-tooltip;
|
|
16
|
+
position-area: top;
|
|
17
|
+
position-try-fallbacks: flip-block;
|
|
18
|
+
margin-block-end: var(--iw-space-2);
|
|
19
|
+
width: max-content;
|
|
8
20
|
z-index: var(--iw-z-tooltip);
|
|
9
21
|
opacity: 0;
|
|
10
22
|
pointer-events: none;
|
|
@@ -15,9 +27,6 @@
|
|
|
15
27
|
padding: var(--iw-space-2) var(--iw-space-3);
|
|
16
28
|
box-shadow: var(--iw-shadow-md);
|
|
17
29
|
transition: opacity 150ms ease;
|
|
18
|
-
left: 50%;
|
|
19
|
-
bottom: calc(100% + var(--iw-space-2));
|
|
20
|
-
transform: translateX(-50%);
|
|
21
30
|
white-space: normal;
|
|
22
31
|
}
|
|
23
32
|
|
|
@@ -38,20 +47,19 @@
|
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
&.iw-tooltip-bottom .iw-tooltip-bubble {
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
position-area: bottom;
|
|
51
|
+
margin: var(--iw-space-2) 0 0;
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
&.iw-tooltip-left .iw-tooltip-bubble {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
transform: translateY(50%);
|
|
55
|
+
position-area: left;
|
|
56
|
+
position-try-fallbacks: flip-inline;
|
|
57
|
+
margin: 0 var(--iw-space-2) 0 0;
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
&.iw-tooltip-right .iw-tooltip-bubble {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
position-area: right;
|
|
62
|
+
position-try-fallbacks: flip-inline;
|
|
63
|
+
margin: 0 0 0 var(--iw-space-2);
|
|
56
64
|
}
|
|
57
65
|
}
|
|
@@ -1028,6 +1028,7 @@ Dialog.render({
|
|
|
1028
1028
|
preview: () =>
|
|
1029
1029
|
Dialog.render({
|
|
1030
1030
|
isOpen: true,
|
|
1031
|
+
isModal: false,
|
|
1031
1032
|
title: "Delete record",
|
|
1032
1033
|
description: "This action cannot be undone.",
|
|
1033
1034
|
actions: previewRow([
|
|
@@ -1173,8 +1174,7 @@ Drawer.render({
|
|
|
1173
1174
|
})`,
|
|
1174
1175
|
preview: () =>
|
|
1175
1176
|
Drawer.render({
|
|
1176
|
-
|
|
1177
|
-
hasBackdrop: false,
|
|
1177
|
+
variant: "permanent",
|
|
1178
1178
|
title: "Navigation",
|
|
1179
1179
|
children: List.render({
|
|
1180
1180
|
items: [
|
|
@@ -1225,7 +1225,8 @@ Link.render({
|
|
|
1225
1225
|
code: `import { Menu } from "@inglorious/ui/menu"
|
|
1226
1226
|
|
|
1227
1227
|
Menu.render({
|
|
1228
|
-
|
|
1228
|
+
id: "record-actions",
|
|
1229
|
+
trigger: "Actions",
|
|
1229
1230
|
items: [
|
|
1230
1231
|
{ label: "Edit" },
|
|
1231
1232
|
{ label: "Duplicate" },
|
|
@@ -1235,7 +1236,8 @@ Menu.render({
|
|
|
1235
1236
|
})`,
|
|
1236
1237
|
preview: () =>
|
|
1237
1238
|
Menu.render({
|
|
1238
|
-
|
|
1239
|
+
id: "record-actions",
|
|
1240
|
+
trigger: "Actions",
|
|
1239
1241
|
items: [
|
|
1240
1242
|
{ label: "Edit" },
|
|
1241
1243
|
{ label: "Duplicate" },
|
|
@@ -1268,7 +1270,6 @@ Pagination.render({
|
|
|
1268
1270
|
code: `import { SpeedDial } from "@inglorious/ui/speed-dial"
|
|
1269
1271
|
|
|
1270
1272
|
SpeedDial.render({
|
|
1271
|
-
isOpen: true,
|
|
1272
1273
|
actions: [
|
|
1273
1274
|
{ label: "Add", icon: "+" },
|
|
1274
1275
|
{ label: "Share", icon: "↗" }
|
|
@@ -1276,7 +1277,6 @@ SpeedDial.render({
|
|
|
1276
1277
|
})`,
|
|
1277
1278
|
preview: () =>
|
|
1278
1279
|
SpeedDial.render({
|
|
1279
|
-
isOpen: true,
|
|
1280
1280
|
actions: [
|
|
1281
1281
|
{ label: "Add", icon: "+" },
|
|
1282
1282
|
{ label: "Share", icon: "↗" },
|
|
@@ -251,17 +251,23 @@
|
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
.iw-primitive-preview .iw-backdrop,
|
|
254
|
-
.iw-primitive-preview .iw-dialog-backdrop,
|
|
255
254
|
.iw-primitive-preview .iw-snackbar,
|
|
256
255
|
.iw-primitive-preview .iw-drawer {
|
|
257
256
|
position: absolute;
|
|
258
257
|
}
|
|
259
258
|
|
|
260
|
-
.iw-primitive-preview .iw-backdrop
|
|
261
|
-
.iw-primitive-preview .iw-dialog-backdrop {
|
|
259
|
+
.iw-primitive-preview .iw-backdrop {
|
|
262
260
|
inset: 0;
|
|
263
261
|
}
|
|
264
262
|
|
|
263
|
+
/* Shown in place (isModal: false), so it can sit in the preview's flow
|
|
264
|
+
rather than where the browser positions a non-modal dialog. */
|
|
265
|
+
.iw-primitive-preview .iw-dialog {
|
|
266
|
+
position: static;
|
|
267
|
+
min-width: 0;
|
|
268
|
+
max-width: 100%;
|
|
269
|
+
}
|
|
270
|
+
|
|
265
271
|
.iw-primitive-preview .iw-drawer {
|
|
266
272
|
top: var(--iw-space-3);
|
|
267
273
|
bottom: var(--iw-space-3);
|
|
@@ -278,8 +284,8 @@
|
|
|
278
284
|
color: var(--iw-color-text-secondary);
|
|
279
285
|
}
|
|
280
286
|
|
|
281
|
-
.iw-dashboard-progress-list .iw-progress-linear
|
|
282
|
-
height: 0.25rem;
|
|
287
|
+
.iw-dashboard-progress-list .iw-progress-linear {
|
|
288
|
+
--iw-progress-height: 0.25rem;
|
|
283
289
|
}
|
|
284
290
|
|
|
285
291
|
.iw-dashboard-user-subtitle {
|
|
@@ -10,7 +10,7 @@ export default {
|
|
|
10
10
|
description: { control: "text" },
|
|
11
11
|
severity: {
|
|
12
12
|
control: "select",
|
|
13
|
-
options: ["info", "success", "warning", "error"],
|
|
13
|
+
options: ["info", "success", "warning", "error", "neutral"],
|
|
14
14
|
},
|
|
15
15
|
variant: { control: "select", options: ["filled", "outlined"] },
|
|
16
16
|
icon: { control: "text" },
|
|
@@ -50,6 +50,14 @@ export const Error = {
|
|
|
50
50
|
},
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
export const Neutral = {
|
|
54
|
+
args: {
|
|
55
|
+
title: "Note",
|
|
56
|
+
description: "A plain remark, with no tone of its own.",
|
|
57
|
+
severity: "neutral",
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
export const Outlined = {
|
|
54
62
|
args: {
|
|
55
63
|
title: "Outlined Alert",
|
|
@@ -81,6 +81,11 @@
|
|
|
81
81
|
--iw-alert-color: var(--iw-color-error, #d14343);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/* A plain note: no tone of its own, just the text colour. */
|
|
85
|
+
.iw-alert-neutral {
|
|
86
|
+
--iw-alert-color: var(--iw-color-text-secondary, var(--iw-color-text));
|
|
87
|
+
}
|
|
88
|
+
|
|
84
89
|
.iw-alert-outlined {
|
|
85
90
|
background: transparent;
|
|
86
91
|
border-color: color-mix(in srgb, var(--iw-alert-color) 55%, transparent);
|
|
@@ -11,7 +11,8 @@ import { applyElementProps } from "../../shared/apply-element-props.js"
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Renders an alert message with optional title, description, icon, and actions.
|
|
14
|
-
* Supports severity and variant styles for info, success, warning, and
|
|
14
|
+
* Supports severity and variant styles for info, success, warning, error and
|
|
15
|
+
* neutral, a plain note.
|
|
15
16
|
* @param {AlertProps} props
|
|
16
17
|
* @returns {TemplateResult}
|
|
17
18
|
*/
|
|
@@ -9,15 +9,19 @@ export default {
|
|
|
9
9
|
render: createRender(Dialog),
|
|
10
10
|
argTypes: {
|
|
11
11
|
isOpen: { control: "boolean" },
|
|
12
|
+
isModal: { control: "boolean" },
|
|
13
|
+
size: { control: "select", options: ["sm", "md", "lg"] },
|
|
12
14
|
title: { control: "text" },
|
|
13
15
|
description: { control: "text" },
|
|
14
16
|
onClose: { action: "onClose" },
|
|
15
17
|
},
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
// In place, so the docs page that shows every story stays usable.
|
|
18
21
|
export const Open = {
|
|
19
22
|
args: {
|
|
20
23
|
isOpen: true,
|
|
24
|
+
isModal: false,
|
|
21
25
|
title: "Delete item",
|
|
22
26
|
description: "This action cannot be undone.",
|
|
23
27
|
children: html`<p>Are you sure you want to continue?</p>`,
|
|
@@ -25,3 +29,30 @@ export const Open = {
|
|
|
25
29
|
<button class="iw-button iw-button-primary">Confirm</button>`,
|
|
26
30
|
},
|
|
27
31
|
}
|
|
32
|
+
|
|
33
|
+
export const Small = {
|
|
34
|
+
args: { ...Open.args, size: "sm" },
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const Medium = {
|
|
38
|
+
args: { ...Open.args, size: "md" },
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const Large = {
|
|
42
|
+
args: {
|
|
43
|
+
...Open.args,
|
|
44
|
+
size: "lg",
|
|
45
|
+
title: "Release notes",
|
|
46
|
+
description: "What changed in this version.",
|
|
47
|
+
children: html`<p>
|
|
48
|
+
A wider dialog, for content that needs the room: tables, previews or
|
|
49
|
+
longer text.
|
|
50
|
+
</p>`,
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Modal takes over the page, so it is left out of the docs page.
|
|
55
|
+
export const Modal = {
|
|
56
|
+
tags: ["!autodocs"],
|
|
57
|
+
args: { ...Open.args, isModal: true },
|
|
58
|
+
}
|
|
@@ -1,23 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
display: flex;
|
|
6
|
-
align-items: center;
|
|
7
|
-
justify-content: center;
|
|
8
|
-
z-index: var(--iw-z-modal, 1050);
|
|
9
|
-
padding: var(--iw-space-4);
|
|
10
|
-
backdrop-filter: blur(2px);
|
|
11
|
-
}
|
|
12
|
-
|
|
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. */
|
|
13
5
|
.iw-dialog {
|
|
14
6
|
background: var(--iw-color-surface);
|
|
15
7
|
color: var(--iw-color-text);
|
|
16
8
|
border-radius: var(--iw-radius-md);
|
|
17
9
|
border: 1px solid color-mix(in srgb, var(--iw-color-border) 70%, transparent);
|
|
10
|
+
box-shadow: var(--iw-shadow-lg, 0 12px 40px rgba(0, 0, 0, 0.3));
|
|
11
|
+
padding: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.iw-dialog-sm {
|
|
15
|
+
min-width: min(20rem, 90vw);
|
|
16
|
+
max-width: min(28rem, 90vw);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.iw-dialog-md {
|
|
18
20
|
min-width: min(32rem, 90vw);
|
|
19
21
|
max-width: min(48rem, 90vw);
|
|
20
|
-
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.iw-dialog-lg {
|
|
25
|
+
min-width: min(40rem, 90vw);
|
|
26
|
+
max-width: min(64rem, 90vw);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.iw-dialog::backdrop {
|
|
30
|
+
background: color-mix(in srgb, var(--iw-color-black) 55%, transparent);
|
|
31
|
+
backdrop-filter: blur(2px);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.iw-dialog-surface {
|
|
21
35
|
padding: var(--iw-space-4);
|
|
22
36
|
}
|
|
23
37
|
|