@hadoku/task-ui-components 0.0.0-stage → 4.20.4
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/LICENSE +21 -0
- package/README.md +917 -2
- package/dist/app-header.css +288 -0
- package/dist/bento.css +143 -0
- package/dist/button.css +227 -0
- package/dist/components/AppHeader.d.ts +61 -0
- package/dist/components/AppHeader.d.ts.map +1 -0
- package/dist/components/AppHeader.js +23 -0
- package/dist/components/AppHeader.js.map +1 -0
- package/dist/components/BentoCard.d.ts +23 -0
- package/dist/components/BentoCard.d.ts.map +1 -0
- package/dist/components/BentoCard.js +49 -0
- package/dist/components/BentoCard.js.map +1 -0
- package/dist/components/BentoGrid.d.ts +24 -0
- package/dist/components/BentoGrid.d.ts.map +1 -0
- package/dist/components/BentoGrid.js +22 -0
- package/dist/components/BentoGrid.js.map +1 -0
- package/dist/components/Button.d.ts +28 -0
- package/dist/components/Button.d.ts.map +1 -0
- package/dist/components/Button.js +51 -0
- package/dist/components/Button.js.map +1 -0
- package/dist/components/ConnectedSettings.d.ts +53 -0
- package/dist/components/ConnectedSettings.d.ts.map +1 -0
- package/dist/components/ConnectedSettings.js +368 -0
- package/dist/components/ConnectedSettings.js.map +1 -0
- package/dist/components/ConnectedThemePicker.d.ts +52 -0
- package/dist/components/ConnectedThemePicker.d.ts.map +1 -0
- package/dist/components/ConnectedThemePicker.js +32 -0
- package/dist/components/ConnectedThemePicker.js.map +1 -0
- package/dist/components/ContextMenu.d.ts +22 -0
- package/dist/components/ContextMenu.d.ts.map +1 -0
- package/dist/components/ContextMenu.js +23 -0
- package/dist/components/ContextMenu.js.map +1 -0
- package/dist/components/HadokuThemePicker.d.ts +27 -0
- package/dist/components/HadokuThemePicker.d.ts.map +1 -0
- package/dist/components/HadokuThemePicker.js +19 -0
- package/dist/components/HadokuThemePicker.js.map +1 -0
- package/dist/components/LoadingSkeleton.d.ts +14 -0
- package/dist/components/LoadingSkeleton.d.ts.map +1 -0
- package/dist/components/LoadingSkeleton.js +62 -0
- package/dist/components/LoadingSkeleton.js.map +1 -0
- package/dist/components/Modal.d.ts +39 -0
- package/dist/components/Modal.d.ts.map +1 -0
- package/dist/components/Modal.js +106 -0
- package/dist/components/Modal.js.map +1 -0
- package/dist/components/NumberInput.d.ts +26 -0
- package/dist/components/NumberInput.d.ts.map +1 -0
- package/dist/components/NumberInput.js +131 -0
- package/dist/components/NumberInput.js.map +1 -0
- package/dist/components/Select.d.ts +52 -0
- package/dist/components/Select.d.ts.map +1 -0
- package/dist/components/Select.js +281 -0
- package/dist/components/Select.js.map +1 -0
- package/dist/components/SettingsModal.d.ts +69 -0
- package/dist/components/SettingsModal.d.ts.map +1 -0
- package/dist/components/SettingsModal.js +141 -0
- package/dist/components/SettingsModal.js.map +1 -0
- package/dist/components/ThemeIcons.d.ts +26 -0
- package/dist/components/ThemeIcons.d.ts.map +1 -0
- package/dist/components/ThemeIcons.js +74 -0
- package/dist/components/ThemeIcons.js.map +1 -0
- package/dist/components/ThemePicker.d.ts +28 -0
- package/dist/components/ThemePicker.d.ts.map +1 -0
- package/dist/components/ThemePicker.js +101 -0
- package/dist/components/ThemePicker.js.map +1 -0
- package/dist/components/Toast.d.ts +13 -0
- package/dist/components/Toast.d.ts.map +1 -0
- package/dist/components/Toast.js +70 -0
- package/dist/components/Toast.js.map +1 -0
- package/dist/components/Toaster.d.ts +19 -0
- package/dist/components/Toaster.d.ts.map +1 -0
- package/dist/components/Toaster.js +19 -0
- package/dist/components/Toaster.js.map +1 -0
- package/dist/components/Tooltip.d.ts +49 -0
- package/dist/components/Tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip.js +143 -0
- package/dist/components/Tooltip.js.map +1 -0
- package/dist/context-menu.css +11 -0
- package/dist/controls.css +137 -0
- package/dist/hooks/useReducedMotion.d.ts +7 -0
- package/dist/hooks/useReducedMotion.d.ts.map +1 -0
- package/dist/hooks/useReducedMotion.js +25 -0
- package/dist/hooks/useReducedMotion.js.map +1 -0
- package/dist/hooks/useToast.d.ts +18 -0
- package/dist/hooks/useToast.d.ts.map +1 -0
- package/dist/hooks/useToast.js +28 -0
- package/dist/hooks/useToast.js.map +1 -0
- package/dist/icon-btn.css +64 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/menuPlacement.d.ts +16 -0
- package/dist/lib/menuPlacement.d.ts.map +1 -0
- package/dist/lib/menuPlacement.js +19 -0
- package/dist/lib/menuPlacement.js.map +1 -0
- package/dist/lib/selectMenus.d.ts +30 -0
- package/dist/lib/selectMenus.d.ts.map +1 -0
- package/dist/lib/selectMenus.js +236 -0
- package/dist/lib/selectMenus.js.map +1 -0
- package/dist/lib/settingsClient.d.ts +144 -0
- package/dist/lib/settingsClient.d.ts.map +1 -0
- package/dist/lib/settingsClient.js +157 -0
- package/dist/lib/settingsClient.js.map +1 -0
- package/dist/lib/themeScope.d.ts +19 -0
- package/dist/lib/themeScope.d.ts.map +1 -0
- package/dist/lib/themeScope.js +10 -0
- package/dist/lib/themeScope.js.map +1 -0
- package/dist/lib/titleTooltips.d.ts +38 -0
- package/dist/lib/titleTooltips.d.ts.map +1 -0
- package/dist/lib/titleTooltips.js +166 -0
- package/dist/lib/titleTooltips.js.map +1 -0
- package/dist/lib/tooltipPlacement.d.ts +14 -0
- package/dist/lib/tooltipPlacement.d.ts.map +1 -0
- package/dist/lib/tooltipPlacement.js +34 -0
- package/dist/lib/tooltipPlacement.js.map +1 -0
- package/dist/modal.css +129 -0
- package/dist/number-input.css +131 -0
- package/dist/scrollbar.css +165 -0
- package/dist/select.css +251 -0
- package/dist/styles.css +1866 -0
- package/dist/task-ui-components.css +1866 -0
- package/dist/theme-picker.css +219 -0
- package/dist/toaster.css +159 -0
- package/dist/tooltip.css +103 -0
- package/dist/types/index.d.ts +37 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +60 -4
- package/src/app-header.css +288 -0
- package/src/bento.css +143 -0
- package/src/button.css +227 -0
- package/src/components/AppHeader.tsx +87 -0
- package/src/components/BentoCard.tsx +72 -0
- package/src/components/BentoGrid.tsx +48 -0
- package/src/components/Button.tsx +81 -0
- package/src/components/ConnectedSettings.tsx +545 -0
- package/src/components/ConnectedThemePicker.tsx +79 -0
- package/src/components/ContextMenu.tsx +48 -0
- package/src/components/HadokuThemePicker.tsx +39 -0
- package/src/components/LoadingSkeleton.tsx +84 -0
- package/src/components/Modal.tsx +171 -0
- package/src/components/NumberInput.tsx +161 -0
- package/src/components/Select.tsx +359 -0
- package/src/components/SettingsModal.tsx +235 -0
- package/src/components/ThemeIcons.tsx +127 -0
- package/src/components/ThemePicker.tsx +149 -0
- package/src/components/Toast.tsx +92 -0
- package/src/components/Toaster.tsx +43 -0
- package/src/components/Tooltip.tsx +212 -0
- package/src/context-menu.css +11 -0
- package/src/controls.css +137 -0
- package/src/hooks/useReducedMotion.ts +36 -0
- package/src/hooks/useToast.ts +57 -0
- package/src/icon-btn.css +64 -0
- package/src/index.ts +153 -0
- package/src/lib/menuPlacement.ts +31 -0
- package/src/lib/selectMenus.ts +303 -0
- package/src/lib/settingsClient.ts +425 -0
- package/src/lib/themeScope.ts +23 -0
- package/src/lib/titleTooltips.ts +236 -0
- package/src/lib/tooltipPlacement.ts +59 -0
- package/src/modal.css +129 -0
- package/src/number-input.css +131 -0
- package/src/scrollbar.css +165 -0
- package/src/select.css +251 -0
- package/src/theme-picker.css +219 -0
- package/src/toaster.css +159 -0
- package/src/tooltip.css +103 -0
- package/src/types/index.ts +43 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a tooltip bubble goes, shared by <Tooltip> and installTitleTooltips so
|
|
3
|
+
* the React and framework-free bubbles sit, flip and clamp identically.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right'
|
|
7
|
+
|
|
8
|
+
export interface Placed {
|
|
9
|
+
side: TooltipPlacement
|
|
10
|
+
left: number
|
|
11
|
+
top: number
|
|
12
|
+
/** Arrow offset along the bubble edge, so it still points at the anchor after clamping. */
|
|
13
|
+
arrow: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const GAP = 8
|
|
17
|
+
const EDGE = 8
|
|
18
|
+
|
|
19
|
+
const OPPOSITE: Record<TooltipPlacement, TooltipPlacement> = {
|
|
20
|
+
top: 'bottom',
|
|
21
|
+
bottom: 'top',
|
|
22
|
+
left: 'right',
|
|
23
|
+
right: 'left'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function fits(side: TooltipPlacement, a: DOMRect, w: number, h: number) {
|
|
27
|
+
if (side === 'top') return a.top - GAP - h >= EDGE
|
|
28
|
+
if (side === 'bottom') return a.bottom + GAP + h <= window.innerHeight - EDGE
|
|
29
|
+
if (side === 'left') return a.left - GAP - w >= EDGE
|
|
30
|
+
return a.right + GAP + w <= window.innerWidth - EDGE
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Onto the device-pixel grid. A bubble at a fractional offset draws its 1px
|
|
34
|
+
* border antialiased across two rows of the screen — a blurred edge. */
|
|
35
|
+
function snap(v: number) {
|
|
36
|
+
const dpr = window.devicePixelRatio || 1
|
|
37
|
+
return Math.round(v * dpr) / dpr
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function placeTooltip(
|
|
41
|
+
preferred: TooltipPlacement,
|
|
42
|
+
a: DOMRect,
|
|
43
|
+
w: number,
|
|
44
|
+
h: number
|
|
45
|
+
): Placed {
|
|
46
|
+
const side =
|
|
47
|
+
fits(preferred, a, w, h) || !fits(OPPOSITE[preferred], a, w, h)
|
|
48
|
+
? preferred
|
|
49
|
+
: OPPOSITE[preferred]
|
|
50
|
+
const clamp = (v: number, max: number) => Math.min(Math.max(v, EDGE), max - EDGE)
|
|
51
|
+
if (side === 'top' || side === 'bottom') {
|
|
52
|
+
const left = snap(clamp(a.left + a.width / 2 - w / 2, window.innerWidth - w))
|
|
53
|
+
const top = snap(side === 'top' ? a.top - GAP - h : a.bottom + GAP)
|
|
54
|
+
return { side, left, top, arrow: a.left + a.width / 2 - left }
|
|
55
|
+
}
|
|
56
|
+
const top = snap(clamp(a.top + a.height / 2 - h / 2, window.innerHeight - h))
|
|
57
|
+
const left = snap(side === 'left' ? a.left - GAP - w : a.right + GAP)
|
|
58
|
+
return { side, left, top, arrow: a.top + a.height / 2 - top }
|
|
59
|
+
}
|
package/src/modal.css
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* Modal styles for @wolffm/task-ui-components.
|
|
2
|
+
*
|
|
3
|
+
* The component shipped without these, which is why it had one adopter: every
|
|
4
|
+
* other app hand-rolled a dialog rather than reproduce the stylesheet. Import
|
|
5
|
+
* alongside the other component CSS:
|
|
6
|
+
* import '@wolffm/task-ui-components/modal.css'
|
|
7
|
+
*
|
|
8
|
+
* Tokens only, so it themes with everything else across all 18 themes.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
.modal-overlay {
|
|
12
|
+
position: fixed;
|
|
13
|
+
inset: 0;
|
|
14
|
+
background-color: var(--color-bg-overlay);
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: flex-start;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
padding: 8vh 16px;
|
|
19
|
+
z-index: 50;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.modal-card {
|
|
23
|
+
background-color: var(--color-bg-card);
|
|
24
|
+
color: var(--color-text);
|
|
25
|
+
border: 1px solid var(--color-border);
|
|
26
|
+
border-radius: var(--hdk-radius-lg);
|
|
27
|
+
padding: 20px;
|
|
28
|
+
width: min(440px, 92vw);
|
|
29
|
+
max-height: 84vh;
|
|
30
|
+
overflow: auto;
|
|
31
|
+
box-shadow: var(--hdk-shadow-lg);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* The card takes focus on open so Escape works before anything inside is
|
|
35
|
+
* focused; it must not draw a focus ring for that. Controls keep theirs. */
|
|
36
|
+
.modal-card:focus {
|
|
37
|
+
outline: none;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* A dialog that needs room — a review step, a side-by-side. */
|
|
41
|
+
.modal-card--wide {
|
|
42
|
+
width: min(680px, 94vw);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.modal-head {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 10px;
|
|
49
|
+
margin: 0 0 14px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.modal-card h3 {
|
|
53
|
+
margin: 0;
|
|
54
|
+
font-size: var(--hdk-text-lg);
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.modal-card label {
|
|
59
|
+
display: block;
|
|
60
|
+
color: var(--color-text-secondary);
|
|
61
|
+
font-size: var(--hdk-text-sm);
|
|
62
|
+
margin: 12px 0 5px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.modal-input {
|
|
66
|
+
width: 100%;
|
|
67
|
+
font: inherit;
|
|
68
|
+
font-size: var(--hdk-text-sm);
|
|
69
|
+
color: var(--color-text);
|
|
70
|
+
background-color: var(--color-bg-alt);
|
|
71
|
+
border: 1px solid var(--color-border);
|
|
72
|
+
border-radius: var(--hdk-radius);
|
|
73
|
+
padding: 9px 11px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.modal-input:focus {
|
|
77
|
+
outline: none;
|
|
78
|
+
border-color: var(--color-primary);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.modal-actions {
|
|
82
|
+
display: flex;
|
|
83
|
+
justify-content: flex-end;
|
|
84
|
+
gap: var(--hdk-space-sm);
|
|
85
|
+
margin-top: 18px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.modal-button {
|
|
89
|
+
font: inherit;
|
|
90
|
+
font-size: var(--hdk-text-sm);
|
|
91
|
+
padding: 8px 14px;
|
|
92
|
+
border-radius: var(--hdk-radius);
|
|
93
|
+
border: 1px solid var(--color-border);
|
|
94
|
+
background: none;
|
|
95
|
+
color: var(--color-text);
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.modal-button:hover:not(:disabled) {
|
|
100
|
+
border-color: var(--color-primary);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.modal-button:disabled {
|
|
104
|
+
opacity: 0.5;
|
|
105
|
+
cursor: not-allowed;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.modal-button--primary {
|
|
109
|
+
background-color: var(--color-primary);
|
|
110
|
+
border-color: var(--color-primary);
|
|
111
|
+
color: var(--color-on-primary);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* The destructive button carries its accent on the border, not the label.
|
|
115
|
+
* `--color-danger` as bare text on the card misses AA in 11 of 18 themes —
|
|
116
|
+
* the same unvalidated accent-over-surface pair that check-usage now gates. */
|
|
117
|
+
.modal-button--danger {
|
|
118
|
+
border-color: var(--color-danger);
|
|
119
|
+
color: var(--color-text);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Filled on hover, so the label takes `on-danger` — NOT `on-primary`, which is
|
|
123
|
+
* derived from primary's luminance and misses AA on a danger fill in 9 of 18
|
|
124
|
+
* themes. `on-danger` over `danger` is the pair check-contrast guarantees. */
|
|
125
|
+
.modal-button--danger:hover:not(:disabled) {
|
|
126
|
+
background-color: var(--color-danger);
|
|
127
|
+
border-color: var(--color-danger);
|
|
128
|
+
color: var(--color-on-danger);
|
|
129
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/* NumberInput styles for @wolffm/task-ui-components.
|
|
2
|
+
*
|
|
3
|
+
* import '@wolffm/task-ui-components/number-input.css'
|
|
4
|
+
*
|
|
5
|
+
* One bordered box holding the field and a stacked up/down stepper, so the
|
|
6
|
+
* focus ring and the border belong to the whole control, as on <Select>.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
.hdk-number {
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
align-items: stretch;
|
|
12
|
+
min-width: 0;
|
|
13
|
+
vertical-align: middle;
|
|
14
|
+
color: var(--color-text);
|
|
15
|
+
background-color: var(--color-bg-card);
|
|
16
|
+
border: 1px solid var(--color-border);
|
|
17
|
+
border-radius: var(--hdk-radius);
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
transition:
|
|
20
|
+
border-color var(--transition-fast),
|
|
21
|
+
box-shadow var(--transition-fast);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.hdk-number:hover:not(.hdk-number--disabled) {
|
|
25
|
+
border-color: var(--color-text-muted);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.hdk-number:focus-within {
|
|
29
|
+
border-color: var(--color-primary);
|
|
30
|
+
box-shadow: var(--hdk-shadow-focus-sm);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.hdk-number--disabled {
|
|
34
|
+
opacity: 0.5;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.hdk-number__input {
|
|
38
|
+
flex: 1;
|
|
39
|
+
width: 100%;
|
|
40
|
+
min-width: 0;
|
|
41
|
+
font: inherit;
|
|
42
|
+
color: inherit;
|
|
43
|
+
background: transparent;
|
|
44
|
+
border: 0;
|
|
45
|
+
appearance: textfield;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.hdk-number__input:focus {
|
|
49
|
+
outline: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.hdk-number__input::-webkit-inner-spin-button,
|
|
53
|
+
.hdk-number__input::-webkit-outer-spin-button {
|
|
54
|
+
appearance: none;
|
|
55
|
+
margin: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.hdk-number__steps {
|
|
59
|
+
display: flex;
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
flex-shrink: 0;
|
|
62
|
+
border-left: 1px solid var(--color-border);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.hdk-number__step {
|
|
66
|
+
display: flex;
|
|
67
|
+
flex: 1;
|
|
68
|
+
align-items: center;
|
|
69
|
+
justify-content: center;
|
|
70
|
+
padding: 0;
|
|
71
|
+
color: var(--color-text-secondary);
|
|
72
|
+
background: transparent;
|
|
73
|
+
border: 0;
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
transition:
|
|
76
|
+
background-color var(--transition-fast),
|
|
77
|
+
color var(--transition-fast);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.hdk-number__step + .hdk-number__step {
|
|
81
|
+
border-top: 1px solid var(--color-border);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.hdk-number__step:hover:not(:disabled) {
|
|
85
|
+
color: var(--color-on-primary-bg);
|
|
86
|
+
background-color: var(--color-primary-bg);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.hdk-number__step:disabled {
|
|
90
|
+
opacity: 0.4;
|
|
91
|
+
cursor: not-allowed;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.hdk-number--sm {
|
|
95
|
+
font-size: var(--hdk-text-xs);
|
|
96
|
+
min-height: 28px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.hdk-number--sm .hdk-number__input {
|
|
100
|
+
padding: 4px 8px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.hdk-number--sm .hdk-number__step {
|
|
104
|
+
width: 18px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.hdk-number--md {
|
|
108
|
+
font-size: var(--hdk-text-sm);
|
|
109
|
+
min-height: 34px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.hdk-number--md .hdk-number__input {
|
|
113
|
+
padding: 7px 10px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.hdk-number--md .hdk-number__step {
|
|
117
|
+
width: 22px;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.hdk-number--lg {
|
|
121
|
+
font-size: var(--hdk-text-base);
|
|
122
|
+
min-height: 42px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.hdk-number--lg .hdk-number__input {
|
|
126
|
+
padding: 10px 12px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.hdk-number--lg .hdk-number__step {
|
|
130
|
+
width: 26px;
|
|
131
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/* Themed scrollbars for @wolffm/task-ui-components.
|
|
2
|
+
*
|
|
3
|
+
* Without this, every scroller renders the platform's bar: a grey Windows
|
|
4
|
+
* gutter on a coffee or cyberpunk surface. `color-scheme` (set per theme in
|
|
5
|
+
* @wolffm/themes) only gets the bar to the right light/dark mode, not the
|
|
6
|
+
* theme's colours.
|
|
7
|
+
*
|
|
8
|
+
* import '@wolffm/task-ui-components/scrollbar.css'
|
|
9
|
+
* <div className="task-app-container hdk-scroll">…</div>
|
|
10
|
+
*
|
|
11
|
+
* `.hdk-scroll` styles the element it is on AND every scroller inside it, so
|
|
12
|
+
* one class on an app's root covers the whole app — hadoku_site puts it on
|
|
13
|
+
* <html>, which covers every micro-frontend at once. The thumb is the theme's
|
|
14
|
+
* primary colour.
|
|
15
|
+
*
|
|
16
|
+
* Every selector is wrapped in `:where()`, so all of this has ZERO
|
|
17
|
+
* specificity: it is a fallback for scrollers nobody styled. Any rule an app
|
|
18
|
+
* writes for a scroller — `scrollbar-width: none` on a carousel, its own
|
|
19
|
+
* `::-webkit-scrollbar` thumb — wins, whatever order the sheets load in.
|
|
20
|
+
* Modifiers sit on the same element:
|
|
21
|
+
*
|
|
22
|
+
* --subtle neutral thumb instead of the accent
|
|
23
|
+
* --thin narrower bar (WebKit/Chromium only; see Firefox below)
|
|
24
|
+
* --rail visible track, so the scroll extent reads at a glance
|
|
25
|
+
* --autohide thumb appears only while that scroller is hovered or focused
|
|
26
|
+
*
|
|
27
|
+
* The colours are declared on EVERY element under the root (`.hdk-scroll *`),
|
|
28
|
+
* not once on it. A custom property inherits its RESOLVED value, so a thumb
|
|
29
|
+
* colour set only on the root would carry the root's theme down into a nested
|
|
30
|
+
* `[data-theme]` scope: a cyberpunk preview inside a coffee app would scroll
|
|
31
|
+
* with coffee's accent. Declared per element, each scroller resolves the
|
|
32
|
+
* tokens of the theme it actually sits in. Sizes are theme-independent and
|
|
33
|
+
* simply inherit.
|
|
34
|
+
*
|
|
35
|
+
* Two engines, two mechanisms. Firefox only knows the standard
|
|
36
|
+
* `scrollbar-color`/`scrollbar-width`, and only ever gets `auto` width —
|
|
37
|
+
* `--thin` included. Under overlay scrollbars (GTK's default on Linux)
|
|
38
|
+
* `thin` draws the idle thumb as a ~1px hairline that antialiases
|
|
39
|
+
* unevenly along its length and only widens on hover; `auto` idles at a solid
|
|
40
|
+
* 2px and hovers at 6px, and with classic scrollbars it is a 6px thumb, the
|
|
41
|
+
* same as the WebKit default below. Chromium and Safari support the
|
|
42
|
+
* `::-webkit-scrollbar` pseudo-elements, which are the only way to get a
|
|
43
|
+
* rounded, inset thumb — but Chromium 121+ IGNORES them whenever
|
|
44
|
+
* `scrollbar-color` or `scrollbar-width` is non-auto, and `scrollbar-color`
|
|
45
|
+
* inherits. So the WebKit branch resets both to `auto`, or a host page that
|
|
46
|
+
* sets `scrollbar-color` on <html> would silently switch all of this off.
|
|
47
|
+
*
|
|
48
|
+
* Everything sits in `@layer hdk-fallbacks`. A rule in a cascade layer loses
|
|
49
|
+
* to every unlayered rule and to every layer declared after it — whatever
|
|
50
|
+
* either's specificity — and Tailwind ships its utilities in layers. Unlayered,
|
|
51
|
+
* even a zero-specificity rule here would beat `bg-primary`. The page must
|
|
52
|
+
* declare the layer FIRST, before any other, so it ranks lowest:
|
|
53
|
+
*
|
|
54
|
+
* @layer hdk-fallbacks, base, theme, utilities;
|
|
55
|
+
*
|
|
56
|
+
* hadoku_site's global.css does that. A sheet that never names it just gets
|
|
57
|
+
* these rules below its own unlayered ones, which is also correct.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
@layer hdk-fallbacks {
|
|
61
|
+
:where(.hdk-scroll) {
|
|
62
|
+
--hdk-scrollbar-size: 10px;
|
|
63
|
+
--hdk-scrollbar-pad: 2px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:where(.hdk-scroll),
|
|
67
|
+
:where(.hdk-scroll *) {
|
|
68
|
+
--hdk-scrollbar-thumb: var(--color-primary);
|
|
69
|
+
--hdk-scrollbar-thumb-hover: var(--color-primary-dark);
|
|
70
|
+
--hdk-scrollbar-track: transparent;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
:where(.hdk-scroll--thin) {
|
|
74
|
+
--hdk-scrollbar-size: 6px;
|
|
75
|
+
--hdk-scrollbar-pad: 1px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:where(.hdk-scroll--subtle),
|
|
79
|
+
:where(.hdk-scroll--subtle *) {
|
|
80
|
+
--hdk-scrollbar-thumb: var(--color-border);
|
|
81
|
+
--hdk-scrollbar-thumb-hover: var(--color-text-muted);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:where(.hdk-scroll--rail) {
|
|
85
|
+
--hdk-scrollbar-size: 12px;
|
|
86
|
+
--hdk-scrollbar-pad: 3px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
:where(.hdk-scroll--rail),
|
|
90
|
+
:where(.hdk-scroll--rail *) {
|
|
91
|
+
--hdk-scrollbar-track: var(--color-bg-hover);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
:where(.hdk-scroll--autohide),
|
|
95
|
+
:where(.hdk-scroll--autohide *) {
|
|
96
|
+
--hdk-scrollbar-thumb: transparent;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* On the hovered/focused element itself, so only that scroller's thumb shows —
|
|
100
|
+
* not every scroller inside an autohide root at once. */
|
|
101
|
+
:where(.hdk-scroll--autohide:hover),
|
|
102
|
+
:where(.hdk-scroll--autohide:focus-within),
|
|
103
|
+
:where(.hdk-scroll--autohide :hover),
|
|
104
|
+
:where(.hdk-scroll--autohide :focus-within) {
|
|
105
|
+
--hdk-scrollbar-thumb: var(--color-primary);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
109
|
+
:where(.hdk-scroll),
|
|
110
|
+
:where(.hdk-scroll *) {
|
|
111
|
+
scrollbar-width: auto;
|
|
112
|
+
scrollbar-color: var(--hdk-scrollbar-thumb) var(--hdk-scrollbar-track);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@supports selector(::-webkit-scrollbar) {
|
|
117
|
+
:where(.hdk-scroll),
|
|
118
|
+
:where(.hdk-scroll *) {
|
|
119
|
+
scrollbar-width: auto;
|
|
120
|
+
scrollbar-color: auto;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
:where(.hdk-scroll)::-webkit-scrollbar,
|
|
124
|
+
:where(.hdk-scroll *)::-webkit-scrollbar {
|
|
125
|
+
width: var(--hdk-scrollbar-size);
|
|
126
|
+
height: var(--hdk-scrollbar-size);
|
|
127
|
+
background-color: var(--hdk-scrollbar-track);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
:where(.hdk-scroll)::-webkit-scrollbar-track,
|
|
131
|
+
:where(.hdk-scroll *)::-webkit-scrollbar-track {
|
|
132
|
+
background-color: var(--hdk-scrollbar-track);
|
|
133
|
+
border-radius: 999px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* The transparent border plus padding-box clip is what insets the thumb
|
|
137
|
+
* from the track edge — a margin does nothing on a scrollbar part. */
|
|
138
|
+
:where(.hdk-scroll)::-webkit-scrollbar-thumb,
|
|
139
|
+
:where(.hdk-scroll *)::-webkit-scrollbar-thumb {
|
|
140
|
+
background-color: var(--hdk-scrollbar-thumb);
|
|
141
|
+
background-clip: padding-box;
|
|
142
|
+
border: var(--hdk-scrollbar-pad) solid transparent;
|
|
143
|
+
border-radius: 999px;
|
|
144
|
+
min-height: 32px;
|
|
145
|
+
min-width: 32px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
:where(.hdk-scroll)::-webkit-scrollbar-thumb:hover,
|
|
149
|
+
:where(.hdk-scroll *)::-webkit-scrollbar-thumb:hover,
|
|
150
|
+
:where(.hdk-scroll)::-webkit-scrollbar-thumb:active,
|
|
151
|
+
:where(.hdk-scroll *)::-webkit-scrollbar-thumb:active {
|
|
152
|
+
background-color: var(--hdk-scrollbar-thumb-hover);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
:where(.hdk-scroll)::-webkit-scrollbar-corner,
|
|
156
|
+
:where(.hdk-scroll *)::-webkit-scrollbar-corner {
|
|
157
|
+
background-color: transparent;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
:where(.hdk-scroll)::-webkit-scrollbar-button,
|
|
161
|
+
:where(.hdk-scroll *)::-webkit-scrollbar-button {
|
|
162
|
+
display: none;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|