@pathscale/ui 3.1.0 → 3.2.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/README.md +13 -2
- package/dist/components/accordion/Accordion.css +24 -1
- package/dist/components/alert/Alert.css +11 -1
- package/dist/components/button/Button.css +33 -6
- package/dist/components/calendar/Calendar.generated.d.ts +19 -2
- package/dist/components/calendar/Calendar.generated.js +30 -23
- package/dist/components/calendar/index.d.ts +1 -1
- package/dist/components/card/Card.generated.d.ts +17 -0
- package/dist/components/card/Card.generated.js +99 -45
- package/dist/components/card/Card.interactions.d.ts +70 -0
- package/dist/components/card/Card.interactions.js +19 -0
- package/dist/components/collapsible/Collapsible.css +17 -1
- package/dist/components/color-wheel-flower/ColorWheelFlower.generated.d.ts +8 -0
- package/dist/components/color-wheel-flower/ColorWheelFlower.generated.js +14 -1
- package/dist/components/color-wheel-flower/colorWheelFlowerContext.d.ts +9 -2
- package/dist/components/color-wheel-flower/colorWheelFlowerContext.js +2 -4
- package/dist/components/date-picker/DatePicker.generated.d.ts +3 -1
- package/dist/components/date-picker/DatePicker.generated.js +8 -5
- package/dist/components/date-range-picker/DateRangePicker.generated.d.ts +3 -1
- package/dist/components/date-range-picker/DateRangePicker.generated.js +9 -6
- package/dist/components/drawer/Drawer.generated.d.ts +24 -0
- package/dist/components/drawer/Drawer.generated.js +48 -18
- package/dist/components/icon/Icon.generated.d.ts +15 -0
- package/dist/components/icon/Icon.generated.js +11 -2
- package/dist/components/immersive-landing/ImmersiveLanding.css +1 -1
- package/dist/components/immersive-landing/components/CookieConsent.interactions.d.ts +24 -0
- package/dist/components/immersive-landing/components/CookieConsent.interactions.js +2 -0
- package/dist/components/immersive-landing/components/CookieConsent.js +52 -47
- package/dist/components/immersive-landing/components/FirefoxPWABanner.js +10 -10
- package/dist/components/immersive-landing/types.d.ts +15 -0
- package/dist/components/language-switcher/LanguageSwitcher.generated.js +1 -1
- package/dist/components/live-chat/LiveChatPanel.generated.js +2 -6
- package/dist/components/live-chat/LiveChatPanel.interactions.d.ts +21 -0
- package/dist/components/live-chat/LiveChatPanel.interactions.js +10 -0
- package/dist/components/popover/Popover.a11y.d.ts +47 -0
- package/dist/components/popover/Popover.a11y.js +19 -0
- package/dist/components/popover/Popover.generated.d.ts +26 -0
- package/dist/components/popover/Popover.generated.js +105 -35
- package/dist/components/range-calendar/RangeCalendar.generated.d.ts +3 -1
- package/dist/components/range-calendar/RangeCalendar.generated.js +4 -1
- package/dist/components/table/MobileListView.generated.js +1 -1
- package/dist/components/text/Text.generated.d.ts +26 -1
- package/dist/components/text/Text.generated.js +13 -8
- package/dist/components/text/index.d.ts +1 -1
- package/dist/components/theme-color-picker/ThemeColorPicker.generated.js +1 -1
- package/dist/hooks/date/date.names.d.ts +107 -0
- package/dist/hooks/date/date.names.js +74 -0
- package/dist/hooks/date/date.utils.d.ts +11 -1
- package/dist/hooks/date/date.utils.js +3 -6
- package/dist/hooks/date/index.d.ts +1 -0
- package/dist/hooks/date/index.js +1 -0
- package/dist/hooks/date/useCalendarState.d.ts +12 -5
- package/dist/hooks/date/useCalendarState.js +7 -19
- package/dist/hooks/form/createForm.d.ts +4 -4
- package/dist/hooks/form/createForm.js +7 -9
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/layouts.manifest.json +4 -1
- package/dist/responsive-classes.txt +450 -0
- package/package.json +10 -5
|
@@ -3,7 +3,8 @@ import { Show, createSignal, onCleanup, onSettled } from "solid-js";
|
|
|
3
3
|
import button_0 from "../../button/index.js";
|
|
4
4
|
import flex from "../../flex/index.js";
|
|
5
5
|
import { CLASSES } from "../ImmersiveLanding.recipe.js";
|
|
6
|
-
|
|
6
|
+
import { dismissesOnBackdropPress } from "./CookieConsent.interactions.js";
|
|
7
|
+
var _tmpl$ = /*#__PURE__*/ template("<p>"), _tmpl$2 = /*#__PURE__*/ template("<div><div>"), _tmpl$3 = /*#__PURE__*/ template("<h2>"), _tmpl$4 = /*#__PURE__*/ template("<label><span></span><input>"), _tmpl$5 = /*#__PURE__*/ template("<div><div><!><!><!>");
|
|
7
8
|
const defaultTexts = {
|
|
8
9
|
message: "We use cookies to improve your experience. You can accept all cookies or manage your preferences.",
|
|
9
10
|
acceptAll: "Accept all",
|
|
@@ -79,6 +80,10 @@ const CookieConsent = (props)=>{
|
|
|
79
80
|
const handleManageClose = ()=>{
|
|
80
81
|
setShowManage(false);
|
|
81
82
|
};
|
|
83
|
+
const handleBackdropClick = (event)=>{
|
|
84
|
+
if (!dismissesOnBackdropPress(event)) return;
|
|
85
|
+
handleManageClose();
|
|
86
|
+
};
|
|
82
87
|
const handleManageSave = ()=>{
|
|
83
88
|
localStorage.setItem(CONSENT_KEY(), "custom");
|
|
84
89
|
localStorage.setItem(ANALYTICS_KEY(), analyticsEnabled().toString());
|
|
@@ -110,7 +115,7 @@ const CookieConsent = (props)=>{
|
|
|
110
115
|
return showBanner();
|
|
111
116
|
},
|
|
112
117
|
get children () {
|
|
113
|
-
var _el$ = _tmpl$
|
|
118
|
+
var _el$ = _tmpl$2(), _el$2 = _el$.firstChild;
|
|
114
119
|
spread(_el$, mergeProps({
|
|
115
120
|
role: "dialog",
|
|
116
121
|
"aria-modal": "false",
|
|
@@ -168,18 +173,18 @@ const CookieConsent = (props)=>{
|
|
|
168
173
|
return texts().decline;
|
|
169
174
|
}
|
|
170
175
|
})),
|
|
171
|
-
((
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
})
|
|
176
|
+
createComponent(button_0, mergeProps({
|
|
177
|
+
type: "button",
|
|
178
|
+
variant: "ghost",
|
|
179
|
+
size: "sm"
|
|
180
|
+
}, ()=>({
|
|
181
|
+
class: CLASSES.cookie.manageButton
|
|
182
|
+
}), {
|
|
183
|
+
onClick: handleManageOpen,
|
|
184
|
+
get children () {
|
|
185
|
+
return texts().manage;
|
|
186
|
+
}
|
|
187
|
+
}))
|
|
183
188
|
];
|
|
184
189
|
}
|
|
185
190
|
}))
|
|
@@ -194,22 +199,22 @@ const CookieConsent = (props)=>{
|
|
|
194
199
|
return showManage();
|
|
195
200
|
},
|
|
196
201
|
get children () {
|
|
197
|
-
var _el$
|
|
198
|
-
spread(_el$
|
|
202
|
+
var _el$4 = _tmpl$5(), _el$5 = _el$4.firstChild, _el$14 = _el$5.firstChild, _el$15 = _el$14.nextSibling, _el$16 = _el$15.nextSibling;
|
|
203
|
+
spread(_el$4, mergeProps({
|
|
199
204
|
role: "dialog",
|
|
200
205
|
"aria-modal": "true",
|
|
201
206
|
"aria-labelledby": "cookie-manage-title"
|
|
202
207
|
}, ()=>({
|
|
203
208
|
class: CLASSES.cookie.modalBackdrop
|
|
204
209
|
}), {
|
|
205
|
-
onClick:
|
|
210
|
+
onClick: handleBackdropClick
|
|
206
211
|
}), true);
|
|
207
|
-
spread(_el$
|
|
212
|
+
spread(_el$5, mergeProps(()=>({
|
|
208
213
|
class: CLASSES.cookie.modalCard
|
|
209
214
|
}), {
|
|
210
215
|
onClick: (e)=>e.stopPropagation()
|
|
211
216
|
}), true);
|
|
212
|
-
insert(_el$
|
|
217
|
+
insert(_el$5, createComponent(flex, mergeProps({
|
|
213
218
|
justify: "between",
|
|
214
219
|
align: "center"
|
|
215
220
|
}, ()=>({
|
|
@@ -218,14 +223,14 @@ const CookieConsent = (props)=>{
|
|
|
218
223
|
get children () {
|
|
219
224
|
return [
|
|
220
225
|
(()=>{
|
|
221
|
-
var _el$
|
|
222
|
-
spread(_el$
|
|
226
|
+
var _el$6 = _tmpl$3();
|
|
227
|
+
spread(_el$6, mergeProps({
|
|
223
228
|
id: "cookie-manage-title"
|
|
224
229
|
}, ()=>({
|
|
225
230
|
class: CLASSES.cookie.modalTitle
|
|
226
231
|
})), true);
|
|
227
|
-
insert(_el$
|
|
228
|
-
return _el$
|
|
232
|
+
insert(_el$6, ()=>texts().manageTitle);
|
|
233
|
+
return _el$6;
|
|
229
234
|
})(),
|
|
230
235
|
createComponent(button_0, {
|
|
231
236
|
size: "sm",
|
|
@@ -239,8 +244,8 @@ const CookieConsent = (props)=>{
|
|
|
239
244
|
})
|
|
240
245
|
];
|
|
241
246
|
}
|
|
242
|
-
})), _el$
|
|
243
|
-
insert(_el$
|
|
247
|
+
})), _el$14);
|
|
248
|
+
insert(_el$5, createComponent(flex, mergeProps({
|
|
244
249
|
direction: "col",
|
|
245
250
|
gap: "md"
|
|
246
251
|
}, ()=>({
|
|
@@ -249,33 +254,33 @@ const CookieConsent = (props)=>{
|
|
|
249
254
|
get children () {
|
|
250
255
|
return [
|
|
251
256
|
(()=>{
|
|
252
|
-
var _el$
|
|
253
|
-
spread(_el$
|
|
257
|
+
var _el$7 = _tmpl$4(), _el$8 = _el$7.firstChild, _el$9 = _el$8.nextSibling;
|
|
258
|
+
spread(_el$7, mergeProps(()=>({
|
|
254
259
|
class: `${CLASSES.cookie.preferenceRow} ${CLASSES.cookie.preferenceRowLocked}`
|
|
255
260
|
})), true);
|
|
256
|
-
spread(_el$
|
|
261
|
+
spread(_el$8, mergeProps(()=>({
|
|
257
262
|
class: CLASSES.cookie.preferenceLabel
|
|
258
263
|
})), true);
|
|
259
|
-
insert(_el$
|
|
260
|
-
spread(_el$
|
|
264
|
+
insert(_el$8, ()=>texts().essential);
|
|
265
|
+
spread(_el$9, mergeProps({
|
|
261
266
|
type: "checkbox",
|
|
262
267
|
checked: true,
|
|
263
268
|
disabled: true
|
|
264
269
|
}, ()=>({
|
|
265
270
|
class: CLASSES.cookie.toggle
|
|
266
271
|
})), false);
|
|
267
|
-
return _el$
|
|
272
|
+
return _el$7;
|
|
268
273
|
})(),
|
|
269
274
|
(()=>{
|
|
270
|
-
var _el$
|
|
271
|
-
spread(_el$
|
|
275
|
+
var _el$0 = _tmpl$4(), _el$1 = _el$0.firstChild, _el$10 = _el$1.nextSibling;
|
|
276
|
+
spread(_el$0, mergeProps(()=>({
|
|
272
277
|
class: CLASSES.cookie.preferenceRow
|
|
273
278
|
})), true);
|
|
274
|
-
spread(_el$
|
|
279
|
+
spread(_el$1, mergeProps(()=>({
|
|
275
280
|
class: CLASSES.cookie.preferenceLabel
|
|
276
281
|
})), true);
|
|
277
|
-
insert(_el$
|
|
278
|
-
spread(_el$
|
|
282
|
+
insert(_el$1, ()=>texts().analytics);
|
|
283
|
+
spread(_el$10, mergeProps({
|
|
279
284
|
type: "checkbox",
|
|
280
285
|
get checked () {
|
|
281
286
|
return analyticsEnabled();
|
|
@@ -284,18 +289,18 @@ const CookieConsent = (props)=>{
|
|
|
284
289
|
}, ()=>({
|
|
285
290
|
class: CLASSES.cookie.toggle
|
|
286
291
|
})), false);
|
|
287
|
-
return _el$
|
|
292
|
+
return _el$0;
|
|
288
293
|
})(),
|
|
289
294
|
(()=>{
|
|
290
|
-
var _el$
|
|
291
|
-
spread(_el$
|
|
295
|
+
var _el$11 = _tmpl$4(), _el$12 = _el$11.firstChild, _el$13 = _el$12.nextSibling;
|
|
296
|
+
spread(_el$11, mergeProps(()=>({
|
|
292
297
|
class: CLASSES.cookie.preferenceRow
|
|
293
298
|
})), true);
|
|
294
|
-
spread(_el$
|
|
299
|
+
spread(_el$12, mergeProps(()=>({
|
|
295
300
|
class: CLASSES.cookie.preferenceLabel
|
|
296
301
|
})), true);
|
|
297
|
-
insert(_el$
|
|
298
|
-
spread(_el$
|
|
302
|
+
insert(_el$12, ()=>texts().marketing);
|
|
303
|
+
spread(_el$13, mergeProps({
|
|
299
304
|
type: "checkbox",
|
|
300
305
|
get checked () {
|
|
301
306
|
return marketingEnabled();
|
|
@@ -304,12 +309,12 @@ const CookieConsent = (props)=>{
|
|
|
304
309
|
}, ()=>({
|
|
305
310
|
class: CLASSES.cookie.toggle
|
|
306
311
|
})), false);
|
|
307
|
-
return _el$
|
|
312
|
+
return _el$11;
|
|
308
313
|
})()
|
|
309
314
|
];
|
|
310
315
|
}
|
|
311
|
-
})), _el$
|
|
312
|
-
insert(_el$
|
|
316
|
+
})), _el$15);
|
|
317
|
+
insert(_el$5, createComponent(flex, mergeProps({
|
|
313
318
|
gap: "sm",
|
|
314
319
|
justify: "end"
|
|
315
320
|
}, ()=>({
|
|
@@ -338,8 +343,8 @@ const CookieConsent = (props)=>{
|
|
|
338
343
|
}))
|
|
339
344
|
];
|
|
340
345
|
}
|
|
341
|
-
})), _el$
|
|
342
|
-
return _el$
|
|
346
|
+
})), _el$16);
|
|
347
|
+
return _el$4;
|
|
343
348
|
}
|
|
344
349
|
})
|
|
345
350
|
];
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createComponent, insert, mergeProps, spread, template } from "@solidjs/web";
|
|
1
|
+
import { createComponent, insert, memo, mergeProps, spread, template } from "@solidjs/web";
|
|
2
2
|
import { Show, createSignal, onSettled } from "solid-js";
|
|
3
3
|
import button_0 from "../../button/index.js";
|
|
4
4
|
import card from "../../card/index.js";
|
|
5
5
|
import flex from "../../flex/index.js";
|
|
6
|
-
import
|
|
6
|
+
import icon_0 from "../../icon/index.js";
|
|
7
7
|
import { CLASSES } from "../ImmersiveLanding.recipe.js";
|
|
8
8
|
var _tmpl$ = /*#__PURE__*/ template("<div>"), _tmpl$2 = /*#__PURE__*/ template("<h3>"), _tmpl$3 = /*#__PURE__*/ template("<p>");
|
|
9
9
|
const defaultTexts = {
|
|
@@ -89,8 +89,8 @@ const FirefoxPWABanner = (props)=>{
|
|
|
89
89
|
return texts().closeLabel;
|
|
90
90
|
},
|
|
91
91
|
get children () {
|
|
92
|
-
return createComponent(
|
|
93
|
-
src: "icon-[
|
|
92
|
+
return createComponent(icon_0, {
|
|
93
|
+
src: "icon-[lucide--x]",
|
|
94
94
|
width: 16,
|
|
95
95
|
height: 16
|
|
96
96
|
});
|
|
@@ -115,17 +115,17 @@ const FirefoxPWABanner = (props)=>{
|
|
|
115
115
|
})), true);
|
|
116
116
|
insert(_el$2, createComponent(Show, {
|
|
117
117
|
get when () {
|
|
118
|
-
return "firefox" === browser();
|
|
118
|
+
return memo(()=>"firefox" === browser())() && props.icon;
|
|
119
119
|
},
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
children: (icon)=>createComponent(icon_0, mergeProps({
|
|
121
|
+
get src () {
|
|
122
|
+
return icon();
|
|
123
|
+
},
|
|
123
124
|
width: 40,
|
|
124
125
|
height: 40
|
|
125
126
|
}, ()=>({
|
|
126
127
|
class: CLASSES.firefoxBanner.browserIcon
|
|
127
|
-
})))
|
|
128
|
-
}
|
|
128
|
+
})))
|
|
129
129
|
}));
|
|
130
130
|
return _el$2;
|
|
131
131
|
})(),
|
|
@@ -115,6 +115,21 @@ export interface FirefoxPWABannerProps {
|
|
|
115
115
|
extensionUrl?: string;
|
|
116
116
|
storageKey?: string;
|
|
117
117
|
texts?: FirefoxPWABannerTexts;
|
|
118
|
+
/**
|
|
119
|
+
* The browser mark shown beside the text. Omit it and the banner renders
|
|
120
|
+
* without one.
|
|
121
|
+
*
|
|
122
|
+
* A default lived here as `icon-[mdi--firefox]`, and it was the only reason
|
|
123
|
+
* this library needed a second Iconify set. Everything else it draws is
|
|
124
|
+
* `lucide`, which has no brand glyphs, so one banner in one optional
|
|
125
|
+
* component obliged every consumer to install all of `-json/mdi` --
|
|
126
|
+
* and a consumer who installed only `lucide` got build warnings and a blank
|
|
127
|
+
* space, which is what happened on crates.vip.
|
|
128
|
+
*
|
|
129
|
+
* Accepts what `Icon` accepts: an Iconify class such as
|
|
130
|
+
* `"icon-[mdi--firefox]"`, or an inline SVG element.
|
|
131
|
+
*/
|
|
132
|
+
icon?: string | JSX.Element;
|
|
118
133
|
onInstall?: () => void;
|
|
119
134
|
onDismiss?: () => void;
|
|
120
135
|
}
|
|
@@ -6,6 +6,7 @@ import { twMerge } from "../../lib/twMerge.js";
|
|
|
6
6
|
import button_0 from "../button/index.js";
|
|
7
7
|
import input from "../input/index.js";
|
|
8
8
|
import { CLASSES, componentRecipe } from "./LiveChat.recipe.js";
|
|
9
|
+
import { formatChatTime } from "./LiveChatPanel.interactions.js";
|
|
9
10
|
var _tmpl$ = /*#__PURE__*/ template("<div>"), _tmpl$2 = /*#__PURE__*/ template('<div><div><div><svg><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path></svg><h3></h3></div><button><svg><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12"></path></svg></button></div><div><!><!></div><div><!><!>'), _tmpl$3 = /*#__PURE__*/ template("<div><div></div><div><div><p></p></div><span>"), _tmpl$4 = /*#__PURE__*/ template("<span>");
|
|
10
11
|
const getMockMessages = ()=>{
|
|
11
12
|
const salesMessages = [
|
|
@@ -59,11 +60,6 @@ const getMockMessages = ()=>{
|
|
|
59
60
|
...supportMessages
|
|
60
61
|
].sort((a, b)=>a.timestamp - b.timestamp);
|
|
61
62
|
};
|
|
62
|
-
const formatTime = (timestamp)=>new Intl.DateTimeFormat("en-US", {
|
|
63
|
-
hour: "numeric",
|
|
64
|
-
minute: "2-digit",
|
|
65
|
-
hour12: true
|
|
66
|
-
}).format(new Date(timestamp));
|
|
67
63
|
const __solidLayoutLiveChatPanel = (_stable, p)=>{
|
|
68
64
|
const others = omit(p, "onClose", "title", "placeholder", "closeLabel", "sendLabel", "emptyMessage", "mockMode", "messages", "onSendMessage", "isSending", "autoScrollOnNewMessage", "autoScrollBehavior", "stickToBottomThreshold", "class", "style");
|
|
69
65
|
const [internalMessages, setInternalMessages] = createSignal([]);
|
|
@@ -267,7 +263,7 @@ const __solidLayoutLiveChatPanel = (_stable, p)=>{
|
|
|
267
263
|
spread(_el$18, mergeProps(()=>({
|
|
268
264
|
class: CLASSES.panel.timestamp
|
|
269
265
|
})), true);
|
|
270
|
-
insert(_el$18, ()=>
|
|
266
|
+
insert(_el$18, ()=>formatChatTime(message.timestamp));
|
|
271
267
|
return _el$13;
|
|
272
268
|
}
|
|
273
269
|
}), _el$0);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A chat timestamp, formatted without `Intl`.
|
|
3
|
+
*
|
|
4
|
+
* The panel used to build its timestamps with
|
|
5
|
+
* `new Intl.DateTimeFormat("en-US", { hour: "numeric", minute: "2-digit",
|
|
6
|
+
* hour12: true })`. `Intl` is not defined in the browser engine the fleet
|
|
7
|
+
* ships, so that constructor threw a `ReferenceError` while a message list was
|
|
8
|
+
* rendering. The consequence is not a wrong timestamp: the error escapes the
|
|
9
|
+
* render, Solid halts its reactive system, and the page keeps painting the
|
|
10
|
+
* frame it already had while every control on it is dead. Measured on
|
|
11
|
+
* pathscale.com, where opening the support chat killed the whole application,
|
|
12
|
+
* and this one call was the only `Intl` reference in that bundle.
|
|
13
|
+
*
|
|
14
|
+
* A clock reading of `3:07 PM` needs no locale database, so this does the
|
|
15
|
+
* conversion with plain `Date` accessors and keeps the `en-US` output byte for
|
|
16
|
+
* byte: a bare 12-hour hour, a colon, two-digit minutes, a space, and `AM` or
|
|
17
|
+
* `PM`. `Meter` guards its `Intl.NumberFormat` in a `try`/`catch` for the same
|
|
18
|
+
* reason; a fallback is not needed here because there is nothing to fall back
|
|
19
|
+
* from.
|
|
20
|
+
*/
|
|
21
|
+
export declare const formatChatTime: (timestamp: number) => string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const formatChatTime = (timestamp)=>{
|
|
2
|
+
const date = new Date(timestamp);
|
|
3
|
+
const hours = date.getHours();
|
|
4
|
+
const minutes = date.getMinutes();
|
|
5
|
+
const hour12 = hours % 12 === 0 ? 12 : hours % 12;
|
|
6
|
+
const suffix = hours < 12 ? "AM" : "PM";
|
|
7
|
+
const paddedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
|
|
8
|
+
return `${hour12}:${paddedMinutes} ${suffix}`;
|
|
9
|
+
};
|
|
10
|
+
export { formatChatTime };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which name reaches the node that carries `role="dialog"`.
|
|
3
|
+
*
|
|
4
|
+
* `role="dialog"` is on `Popover.Content`, because the content is the
|
|
5
|
+
* portalled overlay and `Popover.Dialog` is an optional panel inside it. A
|
|
6
|
+
* reader naming a dialog writes `aria-label` on `Popover.Dialog`, which is the
|
|
7
|
+
* part called Dialog, so the name landed on a generic inside the dialog and
|
|
8
|
+
* named nothing at all. Measured on two sites: every popover dialog in the
|
|
9
|
+
* fleet was anonymous.
|
|
10
|
+
*
|
|
11
|
+
* The name travels up to the role rather than the role travelling down to the
|
|
12
|
+
* name. Moving `role="dialog"` onto `Popover.Dialog` would leave a popover
|
|
13
|
+
* written without one with no dialog, and would make two dialogs of a popover
|
|
14
|
+
* written with two panels.
|
|
15
|
+
*
|
|
16
|
+
* `aria-labelledby` outranks `aria-label` in the accessible name calculation,
|
|
17
|
+
* so a supplied name has to *replace* the fallback reference to the trigger
|
|
18
|
+
* rather than sit beside it. Leaving both would keep the dialog named after
|
|
19
|
+
* the button that opened it while the author's own name was ignored, which is
|
|
20
|
+
* the same silent failure in a new place.
|
|
21
|
+
*/
|
|
22
|
+
export type PopoverDialogNameInput = {
|
|
23
|
+
/** `aria-label` written on `Popover.Content` itself. Outranks everything. */
|
|
24
|
+
contentLabel?: string;
|
|
25
|
+
/** `aria-labelledby` written on `Popover.Content` itself. */
|
|
26
|
+
contentLabelledBy?: string;
|
|
27
|
+
/** `aria-label` written on a `Popover.Dialog` inside the content. */
|
|
28
|
+
dialogLabel?: string;
|
|
29
|
+
/** `aria-labelledby` written on a `Popover.Dialog` inside the content. */
|
|
30
|
+
dialogLabelledBy?: string;
|
|
31
|
+
/** The trigger's id, used only when nothing else names the dialog. */
|
|
32
|
+
triggerId?: string;
|
|
33
|
+
};
|
|
34
|
+
export type PopoverDialogName = {
|
|
35
|
+
"aria-label": string | undefined;
|
|
36
|
+
"aria-labelledby": string | undefined;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* An ARIA attribute value as a name, or nothing.
|
|
40
|
+
*
|
|
41
|
+
* Solid types every `aria-*` attribute as `string | RemoveAttribute`, where the
|
|
42
|
+
* second member is `false` and means "do not emit this". A name is only ever
|
|
43
|
+
* the first, and the second has to become `undefined` before it can be
|
|
44
|
+
* compared, stored or handed to another element.
|
|
45
|
+
*/
|
|
46
|
+
export declare const asAriaName: (value: unknown) => string | undefined;
|
|
47
|
+
export declare const resolvePopoverDialogName: (input: PopoverDialogNameInput) => PopoverDialogName;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const asAriaName = (value)=>"string" == typeof value ? value : void 0;
|
|
2
|
+
const firstNonEmpty = (...values)=>values.find((value)=>void 0 !== value && "" !== value);
|
|
3
|
+
const resolvePopoverDialogName = (input)=>{
|
|
4
|
+
const labelledBy = firstNonEmpty(input.contentLabelledBy, input.dialogLabelledBy);
|
|
5
|
+
const label = firstNonEmpty(input.contentLabel, input.dialogLabel);
|
|
6
|
+
if (void 0 !== labelledBy) return {
|
|
7
|
+
"aria-label": void 0,
|
|
8
|
+
"aria-labelledby": labelledBy
|
|
9
|
+
};
|
|
10
|
+
if (void 0 !== label) return {
|
|
11
|
+
"aria-label": label,
|
|
12
|
+
"aria-labelledby": void 0
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
"aria-label": void 0,
|
|
16
|
+
"aria-labelledby": firstNonEmpty(input.triggerId)
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export { asAriaName, resolvePopoverDialogName };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Component as __LayoutComponent } from "solid-js";
|
|
2
2
|
import "./Popover.css";
|
|
3
3
|
import { type JSX } from "@solidjs/web";
|
|
4
|
+
import { type ValidComponent } from "solid-js";
|
|
4
5
|
import "../_shared/material.css";
|
|
5
6
|
import { type OverlayAnchorRect, type OverlayPlacement } from "../_shared/overlayPosition";
|
|
6
7
|
import type { Material, UIBaseProps } from "../vocabulary";
|
|
@@ -23,6 +24,31 @@ export type PopoverRootProps = UIBaseProps & Omit<JSX.HTMLAttributes<HTMLDivElem
|
|
|
23
24
|
declare const PopoverRoot: __LayoutComponent<PopoverRootProps>;
|
|
24
25
|
export type PopoverTriggerProps = UIBaseProps & Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, "children"> & {
|
|
25
26
|
children: JSX.Element;
|
|
27
|
+
/**
|
|
28
|
+
* The component to be the trigger, instead of a bare button.
|
|
29
|
+
*
|
|
30
|
+
* `Popover.Trigger` renders a `button`, which is right when the trigger is
|
|
31
|
+
* a word or a glyph. It is wrong when the call site hands it a control:
|
|
32
|
+
* `<Popover.Trigger><Button>Filters</Button></Popover.Trigger>` emitted a
|
|
33
|
+
* second, anonymous button wrapping the named one at identical
|
|
34
|
+
* coordinates. Found on three separate sites. Nested interactive content
|
|
35
|
+
* is invalid HTML, and a press by coordinate lands on the anonymous outer
|
|
36
|
+
* one rather than on the control that was written.
|
|
37
|
+
*
|
|
38
|
+
* `as` makes the control *be* the trigger, so there is one element:
|
|
39
|
+
*
|
|
40
|
+
* ```tsx
|
|
41
|
+
* <Popover.Trigger as={Button} flavor="primary">Filters</Popover.Trigger>
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* The wiring -- id, `aria-haspopup`, `aria-expanded`, `aria-controls`, the
|
|
45
|
+
* ref and both handlers -- goes to the delegate, and anything else written
|
|
46
|
+
* here goes with it. The trigger's own class is a button reset and is
|
|
47
|
+
* dropped, because a control does not want one; so is
|
|
48
|
+
* `data-slot="popover-trigger"`, since the delegate's recipe owns that
|
|
49
|
+
* attribute. Select the delegate's own slot, or `[aria-haspopup="dialog"]`.
|
|
50
|
+
*/
|
|
51
|
+
as?: ValidComponent;
|
|
26
52
|
};
|
|
27
53
|
declare const PopoverTrigger: __LayoutComponent<PopoverTriggerProps>;
|
|
28
54
|
export type PopoverContentProps = UIBaseProps & Omit<JSX.HTMLAttributes<HTMLDivElement>, "children"> & {
|