@scalewing/react 1.8.0 → 1.9.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/CHANGELOG.md +140 -0
- package/README.md +69 -2
- package/dist/anchored-position.d.ts +28 -0
- package/dist/anchored-position.js +17 -0
- package/dist/calendar-keys.d.ts +19 -0
- package/dist/calendar-keys.js +39 -0
- package/dist/calendar-labels.d.ts +12 -0
- package/dist/calendar-labels.js +32 -0
- package/dist/calendar-month.d.ts +36 -0
- package/dist/calendar-month.js +111 -0
- package/dist/calendar-years.d.ts +14 -0
- package/dist/calendar-years.js +20 -0
- package/dist/components/Accordion.d.ts +6 -1
- package/dist/components/Accordion.js +12 -3
- package/dist/components/ActionBar.d.ts +30 -0
- package/dist/components/ActionBar.js +13 -0
- package/dist/components/Box.d.ts +7 -3
- package/dist/components/Box.js +2 -2
- package/dist/components/DateField.d.ts +15 -1
- package/dist/components/DateField.js +58 -18
- package/dist/components/Field.d.ts +5 -1
- package/dist/components/Field.js +16 -4
- package/dist/components/FieldAdornment.d.ts +20 -0
- package/dist/components/FieldAdornment.js +34 -0
- package/dist/components/Grid.d.ts +4 -1
- package/dist/components/Grid.js +2 -2
- package/dist/components/Progress.d.ts +3 -1
- package/dist/components/Progress.js +2 -2
- package/dist/components/date-field/CalendarDialog.d.ts +26 -0
- package/dist/components/date-field/CalendarDialog.js +93 -0
- package/dist/components/date-field/CalendarGrid.d.ts +23 -0
- package/dist/components/date-field/CalendarGrid.js +36 -0
- package/dist/components/date-field/CalendarHeader.d.ts +18 -0
- package/dist/components/date-field/CalendarHeader.js +33 -0
- package/dist/components/date-field/DateFieldGlyph.d.ts +9 -0
- package/dist/components/date-field/DateFieldGlyph.js +15 -0
- package/dist/components/date-field/use-anchored-popover.d.ts +8 -0
- package/dist/components/date-field/use-anchored-popover.js +61 -0
- package/dist/components/date-field/use-date-entry.d.ts +20 -0
- package/dist/components/date-field/use-date-entry.js +61 -0
- package/dist/components/date-field/use-lang-locale.d.ts +7 -0
- package/dist/components/date-field/use-lang-locale.js +17 -0
- package/dist/css/css-accordion.js +55 -8
- package/dist/css/css-action-bar.d.ts +4 -0
- package/dist/css/css-action-bar.js +99 -0
- package/dist/css/css-action-menu.js +2 -1
- package/dist/css/css-box-border.d.ts +5 -0
- package/dist/css/css-box-border.js +24 -0
- package/dist/css/css-chrome.js +2 -1
- package/dist/css/css-components.js +10 -6
- package/dist/css/css-data.js +2 -1
- package/dist/css/css-date-field.js +241 -11
- package/dist/css/css-denomination-grid.js +2 -1
- package/dist/css/css-document.d.ts +2 -0
- package/dist/css/css-document.js +2 -1
- package/dist/css/css-field.js +61 -1
- package/dist/css/css-select.js +2 -1
- package/dist/css/css-tooltip.js +2 -1
- package/dist/css/stacking.d.ts +10 -0
- package/dist/css/stacking.js +47 -0
- package/dist/css/stylesheet.js +4 -0
- package/dist/date-entry-validity.d.ts +10 -0
- package/dist/date-entry-validity.js +16 -0
- package/dist/date-entry.d.ts +32 -0
- package/dist/date-entry.js +106 -0
- package/dist/date-field-labels.d.ts +38 -0
- package/dist/date-field-labels.js +22 -0
- package/dist/date-field-locale.d.ts +8 -0
- package/dist/date-field-locale.js +27 -0
- package/dist/date-formatters.d.ts +13 -0
- package/dist/date-formatters.js +28 -0
- package/dist/date-only.d.ts +23 -0
- package/dist/date-only.js +63 -9
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/styles.css +388 -21
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type DateFieldGlyphName = 'calendar' | 'previous' | 'next';
|
|
2
|
+
/**
|
|
3
|
+
* Private control chrome for DateField. Stroke, size, and color come from
|
|
4
|
+
* the generated `sw-date-field-glyph` rule; the chevrons mirror in
|
|
5
|
+
* right-to-left text.
|
|
6
|
+
*/
|
|
7
|
+
export declare function DateFieldGlyph({ name }: {
|
|
8
|
+
name: DateFieldGlyphName;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '../../class-names.js';
|
|
3
|
+
const PATHS = {
|
|
4
|
+
calendar: 'M4 6.5A2.5 2.5 0 0 1 6.5 4h11A2.5 2.5 0 0 1 20 6.5v11a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 4 17.5zM4 10h16M8.5 2.5v3M15.5 2.5v3',
|
|
5
|
+
previous: 'M14.5 6l-6 6 6 6',
|
|
6
|
+
next: 'M9.5 6l6 6-6 6',
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Private control chrome for DateField. Stroke, size, and color come from
|
|
10
|
+
* the generated `sw-date-field-glyph` rule; the chevrons mirror in
|
|
11
|
+
* right-to-left text.
|
|
12
|
+
*/
|
|
13
|
+
export function DateFieldGlyph({ name }) {
|
|
14
|
+
return (_jsx("svg", { "aria-hidden": "true", className: cx('sw-date-field-glyph', name !== 'calendar' && 'sw-date-field-glyph-directional'), focusable: "false", viewBox: "0 0 24 24", children: _jsx("path", { d: PATHS[name] }) }));
|
|
15
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Shows a mounted element on the top layer as a manual popover, keeps it
|
|
4
|
+
* beside `anchorRef` through scroll and resize, and calls `onDismiss` for a
|
|
5
|
+
* press outside it and outside `ignoreRef` (the button that toggles it).
|
|
6
|
+
* Browsers without the popover API get the same fixed placement.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useAnchoredPopover(popoverRef: RefObject<HTMLElement | null>, anchorRef: RefObject<HTMLElement | null>, ignoreRef: RefObject<HTMLElement | null>, onDismiss: () => void): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { spacingScale } from '@scalewing/tokens';
|
|
2
|
+
import { useLayoutEffect, useRef } from 'react';
|
|
3
|
+
import { anchoredPosition } from '../../anchored-position.js';
|
|
4
|
+
function placePopover(node, anchor) {
|
|
5
|
+
const position = anchoredPosition(anchor.getBoundingClientRect(), { width: node.offsetWidth, height: node.offsetHeight }, { width: window.innerWidth, height: window.innerHeight }, {
|
|
6
|
+
gap: spacingScale[1],
|
|
7
|
+
inset: spacingScale[2],
|
|
8
|
+
rtl: getComputedStyle(anchor).direction === 'rtl',
|
|
9
|
+
});
|
|
10
|
+
node.style.left = `${position.left}px`;
|
|
11
|
+
node.style.top = `${position.top}px`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Shows a mounted element on the top layer as a manual popover, keeps it
|
|
15
|
+
* beside `anchorRef` through scroll and resize, and calls `onDismiss` for a
|
|
16
|
+
* press outside it and outside `ignoreRef` (the button that toggles it).
|
|
17
|
+
* Browsers without the popover API get the same fixed placement.
|
|
18
|
+
*/
|
|
19
|
+
export function useAnchoredPopover(popoverRef, anchorRef, ignoreRef, onDismiss) {
|
|
20
|
+
const dismissRef = useRef(onDismiss);
|
|
21
|
+
useLayoutEffect(() => {
|
|
22
|
+
dismissRef.current = onDismiss;
|
|
23
|
+
});
|
|
24
|
+
useLayoutEffect(() => {
|
|
25
|
+
const node = popoverRef.current;
|
|
26
|
+
const anchor = anchorRef.current;
|
|
27
|
+
if (!node || !anchor)
|
|
28
|
+
return;
|
|
29
|
+
const supportsPopover = typeof node.showPopover === 'function';
|
|
30
|
+
// Set only where supported: an unsupported runtime would hide a
|
|
31
|
+
// `[popover]` element that it can never show.
|
|
32
|
+
if (supportsPopover) {
|
|
33
|
+
node.setAttribute('popover', 'manual');
|
|
34
|
+
if (!node.matches(':popover-open'))
|
|
35
|
+
node.showPopover();
|
|
36
|
+
}
|
|
37
|
+
placePopover(node, anchor);
|
|
38
|
+
function onPointerDown(event) {
|
|
39
|
+
const target = event.target;
|
|
40
|
+
if (!(target instanceof Node))
|
|
41
|
+
return;
|
|
42
|
+
if (node?.contains(target) || ignoreRef.current?.contains(target))
|
|
43
|
+
return;
|
|
44
|
+
dismissRef.current();
|
|
45
|
+
}
|
|
46
|
+
function onMove() {
|
|
47
|
+
if (node && anchor)
|
|
48
|
+
placePopover(node, anchor);
|
|
49
|
+
}
|
|
50
|
+
document.addEventListener('pointerdown', onPointerDown);
|
|
51
|
+
window.addEventListener('resize', onMove);
|
|
52
|
+
window.addEventListener('scroll', onMove, true);
|
|
53
|
+
return () => {
|
|
54
|
+
document.removeEventListener('pointerdown', onPointerDown);
|
|
55
|
+
window.removeEventListener('resize', onMove);
|
|
56
|
+
window.removeEventListener('scroll', onMove, true);
|
|
57
|
+
if (supportsPopover && node.matches(':popover-open'))
|
|
58
|
+
node.hidePopover();
|
|
59
|
+
};
|
|
60
|
+
}, [anchorRef, ignoreRef, popoverRef]);
|
|
61
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type DateEntryPattern } from '../../date-entry.js';
|
|
2
|
+
export type DateEntry = {
|
|
3
|
+
text: string;
|
|
4
|
+
/** The date the text forms: YYYY-MM-DD, '' when blank, null when not one. */
|
|
5
|
+
parsed: string | null;
|
|
6
|
+
/** Typed text that is not a date, after the person left the field. */
|
|
7
|
+
invalid: boolean;
|
|
8
|
+
change: (text: string) => void;
|
|
9
|
+
check: () => void;
|
|
10
|
+
reset: () => void;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Typed entry over a controlled date-only value. A keystroke that finishes
|
|
14
|
+
* a date (see `isCompleteDateEntry`) or blanks the text calls `onCommit`;
|
|
15
|
+
* a date whose last field may still grow commits on `check` (blur or
|
|
16
|
+
* Enter). Text that is not (yet) a date stays on screen and leaves the value
|
|
17
|
+
* alone. The text also stays when the parent keeps the old value; when
|
|
18
|
+
* `value` changes from outside to any other date, the text follows it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useDateEntry(value: string, pattern: DateEntryPattern, onCommit: (value: string) => void): DateEntry;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { formatDateEntry, isCompleteDateEntry, parseDateEntry, } from '../../date-entry.js';
|
|
3
|
+
/**
|
|
4
|
+
* Typed entry over a controlled date-only value. A keystroke that finishes
|
|
5
|
+
* a date (see `isCompleteDateEntry`) or blanks the text calls `onCommit`;
|
|
6
|
+
* a date whose last field may still grow commits on `check` (blur or
|
|
7
|
+
* Enter). Text that is not (yet) a date stays on screen and leaves the value
|
|
8
|
+
* alone. The text also stays when the parent keeps the old value; when
|
|
9
|
+
* `value` changes from outside to any other date, the text follows it.
|
|
10
|
+
*/
|
|
11
|
+
export function useDateEntry(value, pattern, onCommit) {
|
|
12
|
+
const [draft, setDraft] = useState(null);
|
|
13
|
+
const current = draft !== null && (draft.value === value || draft.committed === value)
|
|
14
|
+
? draft
|
|
15
|
+
: null;
|
|
16
|
+
// The parent adopted the commit: tie the text to it, so a later outside
|
|
17
|
+
// change back to the old value replaces the text.
|
|
18
|
+
if (current !== null && current.value !== value)
|
|
19
|
+
setDraft({ ...current, value, committed: null });
|
|
20
|
+
const text = current ? current.text : formatDateEntry(value, pattern);
|
|
21
|
+
const parsed = parseDateEntry(text, pattern);
|
|
22
|
+
function change(next) {
|
|
23
|
+
const nextValue = parseDateEntry(next, pattern);
|
|
24
|
+
const ready = nextValue === '' ||
|
|
25
|
+
(nextValue !== null && isCompleteDateEntry(next, pattern));
|
|
26
|
+
const committed = ready && nextValue !== value ? nextValue : null;
|
|
27
|
+
setDraft({ text: next, value, committed, checked: false });
|
|
28
|
+
if (committed !== null)
|
|
29
|
+
onCommit(committed);
|
|
30
|
+
}
|
|
31
|
+
function check() {
|
|
32
|
+
if (current === null)
|
|
33
|
+
return;
|
|
34
|
+
if (parsed === null) {
|
|
35
|
+
setDraft({ ...current, checked: true });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (parsed === value) {
|
|
39
|
+
// Show the value in the locale's padded form.
|
|
40
|
+
setDraft(null);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Commit once; a parent that keeps the old value keeps the padded text.
|
|
44
|
+
if (parsed !== current.committed)
|
|
45
|
+
onCommit(parsed);
|
|
46
|
+
setDraft({
|
|
47
|
+
text: formatDateEntry(parsed, pattern),
|
|
48
|
+
value,
|
|
49
|
+
committed: parsed,
|
|
50
|
+
checked: false,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
text,
|
|
55
|
+
parsed,
|
|
56
|
+
invalid: current !== null && current.checked && parsed === null,
|
|
57
|
+
change,
|
|
58
|
+
check,
|
|
59
|
+
reset: () => setDraft(null),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The `locale` prop when given; otherwise the `lang` of the nearest ancestor
|
|
4
|
+
* of `ref`, read when the field mounts, then en-US. A product that switches
|
|
5
|
+
* language without remounting passes `locale`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useLangLocale(locale: string | undefined, ref: RefObject<HTMLElement | null>): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useLayoutEffect, useState } from 'react';
|
|
2
|
+
import { resolveDateLocale } from '../../date-field-locale.js';
|
|
3
|
+
/**
|
|
4
|
+
* The `locale` prop when given; otherwise the `lang` of the nearest ancestor
|
|
5
|
+
* of `ref`, read when the field mounts, then en-US. A product that switches
|
|
6
|
+
* language without remounting passes `locale`.
|
|
7
|
+
*/
|
|
8
|
+
export function useLangLocale(locale, ref) {
|
|
9
|
+
const [lang, setLang] = useState(null);
|
|
10
|
+
useLayoutEffect(() => {
|
|
11
|
+
if (locale !== undefined)
|
|
12
|
+
return;
|
|
13
|
+
const nearest = ref.current?.closest('[lang]')?.getAttribute('lang');
|
|
14
|
+
setLang(nearest ?? null);
|
|
15
|
+
}, [locale, ref]);
|
|
16
|
+
return resolveDateLocale(locale, lang);
|
|
17
|
+
}
|
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
function markerRules() {
|
|
2
|
+
return `/* A token chevron replaces the user-agent triangle: it points to the inline end when closed and down when open. */
|
|
3
|
+
.sw-accordion-summary::-webkit-details-marker { display: none; }
|
|
4
|
+
|
|
5
|
+
.sw-accordion-marker {
|
|
6
|
+
border-bottom: 2px solid var(--sw-color-muted);
|
|
7
|
+
border-right: 2px solid var(--sw-color-muted);
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
flex: none;
|
|
10
|
+
height: var(--sw-space-2);
|
|
11
|
+
margin-inline-end: var(--sw-space-1);
|
|
12
|
+
transform: rotate(-45deg);
|
|
13
|
+
transition: transform var(--sw-motion-default) var(--sw-motion-easing);
|
|
14
|
+
width: var(--sw-space-2);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.sw-accordion-marker:dir(rtl) { transform: rotate(135deg); }
|
|
18
|
+
|
|
19
|
+
.sw-accordion[open] > .sw-accordion-summary .sw-accordion-marker {
|
|
20
|
+
transform: rotate(45deg);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@media (prefers-reduced-motion: reduce) {
|
|
24
|
+
.sw-accordion-marker { transition: none; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@media (forced-colors: active) {
|
|
28
|
+
.sw-accordion-marker { border-color: CanvasText; }
|
|
29
|
+
}`;
|
|
30
|
+
}
|
|
1
31
|
export function cssAccordionClasses() {
|
|
2
32
|
return `.sw-accordion {
|
|
3
33
|
background: var(--sw-glass-fill);
|
|
@@ -9,25 +39,42 @@ export function cssAccordionClasses() {
|
|
|
9
39
|
color: var(--sw-color-text);
|
|
10
40
|
}
|
|
11
41
|
|
|
42
|
+
/* A nested disclosure sits inside a larger surface, so its corners are smaller. */
|
|
43
|
+
.sw-accordion-sm { border-radius: var(--sw-radius-md); }
|
|
44
|
+
|
|
12
45
|
.sw-accordion-summary {
|
|
46
|
+
align-items: center;
|
|
47
|
+
box-sizing: border-box;
|
|
13
48
|
cursor: pointer;
|
|
14
|
-
display:
|
|
49
|
+
display: flex;
|
|
50
|
+
gap: var(--sw-space-3);
|
|
51
|
+
list-style: none;
|
|
15
52
|
min-height: var(--sw-control-md-min-height);
|
|
16
53
|
}
|
|
17
54
|
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
}
|
|
55
|
+
/* A nested header is an sm control, still a comfortable pointer and touch target. */
|
|
56
|
+
.sw-accordion-sm > .sw-accordion-summary { min-height: var(--sw-control-sm-min-height); }
|
|
21
57
|
|
|
22
|
-
.sw-accordion-
|
|
23
|
-
|
|
58
|
+
.sw-accordion-heading {
|
|
59
|
+
display: flex;
|
|
60
|
+
flex: 1 1 auto;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
min-width: 0;
|
|
24
63
|
}
|
|
25
64
|
|
|
26
65
|
.sw-accordion-summary:focus-visible {
|
|
27
66
|
outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
|
|
28
67
|
outline-offset: var(--sw-focus-ring-offset);
|
|
29
|
-
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
${markerRules()}`;
|
|
30
71
|
}
|
|
31
72
|
export function accordionClassCatalog() {
|
|
32
|
-
return [
|
|
73
|
+
return [
|
|
74
|
+
'sw-accordion',
|
|
75
|
+
'sw-accordion-sm',
|
|
76
|
+
'sw-accordion-summary',
|
|
77
|
+
'sw-accordion-heading',
|
|
78
|
+
'sw-accordion-marker',
|
|
79
|
+
];
|
|
33
80
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { breakpointQuery, breakpoints, } from './breakpoints.js';
|
|
3
|
+
import { zIndex } from './stacking.js';
|
|
4
|
+
const caption = typographyVariants.caption;
|
|
5
|
+
/* The bar floats a step above the bottom edge and clears the home indicator. */
|
|
6
|
+
function stuckToBottom(indent) {
|
|
7
|
+
return [
|
|
8
|
+
'bottom: calc(var(--sw-space-2) + env(safe-area-inset-bottom, 0px));',
|
|
9
|
+
'position: sticky;',
|
|
10
|
+
zIndex('bottomChrome'),
|
|
11
|
+
]
|
|
12
|
+
.map((declaration) => `${indent}${declaration}`)
|
|
13
|
+
.join('\n');
|
|
14
|
+
}
|
|
15
|
+
export function actionBarStickyClass(stickyBelow) {
|
|
16
|
+
return stickyBelow
|
|
17
|
+
? `sw-action-bar-sticky-below-${stickyBelow}`
|
|
18
|
+
: 'sw-action-bar-sticky';
|
|
19
|
+
}
|
|
20
|
+
function stickyRules() {
|
|
21
|
+
const below = breakpoints
|
|
22
|
+
.map((breakpoint) => `@media ${breakpointQuery('below', breakpoint)} {
|
|
23
|
+
.${actionBarStickyClass(breakpoint)} {
|
|
24
|
+
${stuckToBottom(' ')}
|
|
25
|
+
}
|
|
26
|
+
}`)
|
|
27
|
+
.join('\n\n');
|
|
28
|
+
return `.sw-action-bar-sticky {
|
|
29
|
+
${stuckToBottom(' ')}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
${below}`;
|
|
33
|
+
}
|
|
34
|
+
export function cssActionBarClasses() {
|
|
35
|
+
return `.sw-action-bar {
|
|
36
|
+
align-items: center;
|
|
37
|
+
background: var(--sw-glass-fill);
|
|
38
|
+
border: 1px solid var(--sw-glass-border);
|
|
39
|
+
border-radius: var(--sw-radius-lg);
|
|
40
|
+
box-shadow: inset 0 1px 0 var(--sw-glass-specular);
|
|
41
|
+
backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
42
|
+
-webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
43
|
+
box-sizing: border-box;
|
|
44
|
+
color: var(--sw-color-text);
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-wrap: wrap;
|
|
47
|
+
gap: var(--sw-space-2) var(--sw-space-4);
|
|
48
|
+
padding-block: var(--sw-space-3);
|
|
49
|
+
padding-left: max(var(--sw-space-4), env(safe-area-inset-left, 0px));
|
|
50
|
+
padding-right: max(var(--sw-space-4), env(safe-area-inset-right, 0px));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.sw-action-bar-status {
|
|
54
|
+
color: var(--sw-color-muted);
|
|
55
|
+
flex: 1 1 auto;
|
|
56
|
+
font-family: var(--sw-font-sans);
|
|
57
|
+
font-size: ${caption.fontSize}px;
|
|
58
|
+
line-height: ${caption.lineHeight}px;
|
|
59
|
+
margin: 0;
|
|
60
|
+
min-width: 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* With no status the live region stays in the page, so a first status is
|
|
64
|
+
still announced, but it takes no room in the bar. */
|
|
65
|
+
.sw-action-bar-status:empty {
|
|
66
|
+
clip-path: inset(50%);
|
|
67
|
+
height: 1px;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
position: absolute;
|
|
70
|
+
width: 1px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.sw-action-bar-actions {
|
|
74
|
+
align-items: center;
|
|
75
|
+
display: flex;
|
|
76
|
+
flex: 0 1 auto;
|
|
77
|
+
flex-wrap: wrap;
|
|
78
|
+
gap: var(--sw-space-2);
|
|
79
|
+
justify-content: flex-end;
|
|
80
|
+
margin-inline-start: auto;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@media ${breakpointQuery('below', 'md')} {
|
|
84
|
+
.sw-action-bar-status,
|
|
85
|
+
.sw-action-bar-actions { flex-basis: 100%; }
|
|
86
|
+
.sw-action-bar-actions > * { flex: 1 1 auto; }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
${stickyRules()}`;
|
|
90
|
+
}
|
|
91
|
+
export function actionBarClassCatalog() {
|
|
92
|
+
return [
|
|
93
|
+
'sw-action-bar',
|
|
94
|
+
'sw-action-bar-status',
|
|
95
|
+
'sw-action-bar-actions',
|
|
96
|
+
'sw-action-bar-sticky',
|
|
97
|
+
...breakpoints.map((breakpoint) => actionBarStickyClass(breakpoint)),
|
|
98
|
+
];
|
|
99
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { zIndex } from './stacking.js';
|
|
2
3
|
const label = typographyVariants.label;
|
|
3
4
|
export function cssActionMenuClasses() {
|
|
4
5
|
return `.sw-action-menu {
|
|
@@ -45,7 +46,7 @@ export function cssActionMenuClasses() {
|
|
|
45
46
|
overflow: auto;
|
|
46
47
|
padding: var(--sw-space-1);
|
|
47
48
|
position: fixed;
|
|
48
|
-
|
|
49
|
+
${zIndex('popup')}
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
.sw-action-menu-list[hidden] {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type BoxBorderValue = boolean | 'dashed';
|
|
2
|
+
/** The generated class for a Box `border` prop, or none for `false`. */
|
|
3
|
+
export declare function boxBorderClass(border: BoxBorderValue | undefined): string | undefined;
|
|
4
|
+
export declare function cssBoxBorderClasses(): string;
|
|
5
|
+
export declare function boxBorderClassCatalog(): string[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const borderStyles = ['solid', 'dashed'];
|
|
2
|
+
function borderClass(style) {
|
|
3
|
+
return style === 'solid' ? 'sw-border' : `sw-border-${style}`;
|
|
4
|
+
}
|
|
5
|
+
/** The generated class for a Box `border` prop, or none for `false`. */
|
|
6
|
+
export function boxBorderClass(border) {
|
|
7
|
+
if (!border)
|
|
8
|
+
return undefined;
|
|
9
|
+
return borderClass(border === 'dashed' ? 'dashed' : 'solid');
|
|
10
|
+
}
|
|
11
|
+
/*
|
|
12
|
+
* A Box `border` is a token hairline. These rules are emitted after every
|
|
13
|
+
* component rule so that, at equal specificity, the prop still wins over a
|
|
14
|
+
* Box-based component's own frame. A consumer `style` wins over both. In
|
|
15
|
+
* forced colors the system border color replaces the token and the style stays.
|
|
16
|
+
*/
|
|
17
|
+
export function cssBoxBorderClasses() {
|
|
18
|
+
return borderStyles
|
|
19
|
+
.map((style) => `.${borderClass(style)} { border: 1px ${style} var(--sw-color-border); }`)
|
|
20
|
+
.join('\n');
|
|
21
|
+
}
|
|
22
|
+
export function boxBorderClassCatalog() {
|
|
23
|
+
return borderStyles.map(borderClass);
|
|
24
|
+
}
|
package/dist/css/css-chrome.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { zIndex } from './stacking.js';
|
|
2
3
|
const caption = typographyVariants.caption;
|
|
3
4
|
const label = typographyVariants.label;
|
|
4
5
|
export function cssChromeClasses() {
|
|
@@ -14,7 +15,7 @@ export function cssChromeClasses() {
|
|
|
14
15
|
.sw-app-header-sticky {
|
|
15
16
|
position: sticky;
|
|
16
17
|
top: 0;
|
|
17
|
-
|
|
18
|
+
${zIndex('topChrome')}
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
.sw-nav {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { compactTypographyVariants, typographyVariants, } from '@scalewing/tokens';
|
|
2
2
|
import { breakpointQuery } from './breakpoints.js';
|
|
3
|
+
import { cssActionBarClasses } from './css-action-bar.js';
|
|
3
4
|
import { cssActionMenuClasses } from './css-action-menu.js';
|
|
4
5
|
import { cssAccordionClasses } from './css-accordion.js';
|
|
5
6
|
import { cssButtonClasses } from './css-button.js';
|
|
@@ -26,6 +27,8 @@ import { cssGridSpanClasses } from './css-grid-span.js';
|
|
|
26
27
|
import { cssDenominationGridClasses } from './css-denomination-grid.js';
|
|
27
28
|
import { cssFieldClasses } from './css-field.js';
|
|
28
29
|
import { cssToastClasses } from './css-toast.js';
|
|
30
|
+
import { cssBoxBorderClasses } from './css-box-border.js';
|
|
31
|
+
import { cssPopupHostRules } from './stacking.js';
|
|
29
32
|
/*
|
|
30
33
|
* Reduce Transparency swaps every glass surface for the solid surface. It is
|
|
31
34
|
* emitted after every component rule: at equal specificity the later rule wins,
|
|
@@ -35,6 +38,7 @@ function reducedTransparencyRules() {
|
|
|
35
38
|
return `@media (prefers-reduced-transparency: reduce) {
|
|
36
39
|
.sw-card-glass,
|
|
37
40
|
.sw-app-header,
|
|
41
|
+
.sw-action-bar,
|
|
38
42
|
.sw-badge-neutral,
|
|
39
43
|
.sw-segmented,
|
|
40
44
|
.sw-table-sticky thead th,
|
|
@@ -45,6 +49,7 @@ function reducedTransparencyRules() {
|
|
|
45
49
|
.sw-accordion,
|
|
46
50
|
.sw-select-list,
|
|
47
51
|
.sw-action-menu-list,
|
|
52
|
+
.sw-date-field-calendar,
|
|
48
53
|
.sw-toast {
|
|
49
54
|
background: var(--sw-color-surface);
|
|
50
55
|
backdrop-filter: none;
|
|
@@ -82,12 +87,7 @@ export function cssComponentClasses() {
|
|
|
82
87
|
-webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
83
88
|
}
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
.sw-card-glass:has(.sw-select-list, .sw-action-menu-list:not([hidden]), .sw-tooltip:not([hidden])),
|
|
87
|
-
.sw-accordion:has(.sw-select-list, .sw-action-menu-list:not([hidden]), .sw-tooltip:not([hidden])) {
|
|
88
|
-
position: relative;
|
|
89
|
-
z-index: 1;
|
|
90
|
-
}
|
|
90
|
+
${cssPopupHostRules()}
|
|
91
91
|
|
|
92
92
|
.sw-card-outlined {
|
|
93
93
|
background: var(--sw-color-surface);
|
|
@@ -145,6 +145,8 @@ ${cssSelectClasses()}
|
|
|
145
145
|
|
|
146
146
|
${cssActionMenuClasses()}
|
|
147
147
|
|
|
148
|
+
${cssActionBarClasses()}
|
|
149
|
+
|
|
148
150
|
${cssSwitchClasses()}
|
|
149
151
|
|
|
150
152
|
${cssSpinnerClasses()}
|
|
@@ -173,5 +175,7 @@ ${cssToastClasses()}
|
|
|
173
175
|
|
|
174
176
|
${cssResponsiveClasses()}
|
|
175
177
|
|
|
178
|
+
${cssBoxBorderClasses()}
|
|
179
|
+
|
|
176
180
|
${reducedTransparencyRules()}`;
|
|
177
181
|
}
|
package/dist/css/css-data.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { trackInset, typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
import { scrollRegionRules } from './css-scroll-region.js';
|
|
3
|
+
import { zIndex } from './stacking.js';
|
|
3
4
|
export const badgeTones = [
|
|
4
5
|
'neutral',
|
|
5
6
|
'accent',
|
|
@@ -180,7 +181,7 @@ ${scrollRegionRules('.sw-table-wrap')}
|
|
|
180
181
|
-webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
181
182
|
position: sticky;
|
|
182
183
|
top: 0;
|
|
183
|
-
|
|
184
|
+
${zIndex('stickyCell')}
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
.sw-table-compact th,
|