@bagelink/vue 1.15.102 → 1.15.106
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/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
- package/dist/composables/useTheme.d.ts +10 -2
- package/dist/composables/useTheme.d.ts.map +1 -1
- package/dist/dialog/Dialog.vue.d.ts.map +1 -1
- package/dist/index.cjs +34 -34
- package/dist/index.mjs +4650 -4645
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/form/inputs/ColorInput.vue +13 -8
- package/src/composables/useTheme.ts +49 -9
- package/src/dialog/Dialog.vue +11 -2
- package/src/styles/dark.css +5 -31
package/package.json
CHANGED
|
@@ -51,12 +51,12 @@ watch(
|
|
|
51
51
|
}"
|
|
52
52
|
>
|
|
53
53
|
<input
|
|
54
|
-
:id="id" v-model="inputVal"
|
|
54
|
+
:id="id" v-model="inputVal" type="color" :placeholder="resolveI18n(placeholder) || resolveI18n(label)"
|
|
55
55
|
:class="{ 'no-edit': !editMode, 'opacity-1': !inputVal }" :required="required"
|
|
56
56
|
v-bind="nativeInputAttrs"
|
|
57
57
|
>
|
|
58
58
|
<input
|
|
59
|
-
v-if="!small" v-model="inputVal" class="flex-grow-1
|
|
59
|
+
v-if="!small" v-model="inputVal" class="flex-grow-1 colorInputPick" type="text"
|
|
60
60
|
:placeholder="$t('color.placeholder')"
|
|
61
61
|
>
|
|
62
62
|
<Btn
|
|
@@ -78,6 +78,17 @@ min-width: 50px !important;
|
|
|
78
78
|
outline: none !important;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
/* Frame/outline belongs to the wrap only — suppress the global variant rules
|
|
82
|
+
(e.g. `.bagel-input.bgl-outline input`) that would border the inner field. */
|
|
83
|
+
.bagel-input .colorInputPick,
|
|
84
|
+
.bagel-input.frame .colorInputPick,
|
|
85
|
+
.bagel-input.bgl-outline .colorInputPick,
|
|
86
|
+
.bagel-input.underlined .colorInputPick {
|
|
87
|
+
border: none !important;
|
|
88
|
+
outline: none !important;
|
|
89
|
+
box-shadow: none !important;
|
|
90
|
+
}
|
|
91
|
+
|
|
81
92
|
.colorInputPick:focus,
|
|
82
93
|
.colorInputPick:focus-visible {
|
|
83
94
|
outline: none !important;
|
|
@@ -88,7 +99,6 @@ box-shadow: none !important;
|
|
|
88
99
|
box-shadow: inset 0 0 10px #00000021;
|
|
89
100
|
}
|
|
90
101
|
|
|
91
|
-
/* ── frame: transparent bg, outline that highlights on focus ── */
|
|
92
102
|
.bagel-input.frame .colorInputPickWrap {
|
|
93
103
|
background: transparent !important;
|
|
94
104
|
outline: 1.5px solid var(--bgl-border-color);
|
|
@@ -100,20 +110,16 @@ outline-color: var(--bgl-input-label-active-color, var(--bgl-primary));
|
|
|
100
110
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--bgl-input-label-active-color, var(--bgl-primary)) 12%, transparent);
|
|
101
111
|
}
|
|
102
112
|
|
|
103
|
-
/* ── bgl-outline: border only ── */
|
|
104
113
|
.bagel-input.bgl-outline .colorInputPickWrap {
|
|
105
114
|
outline: 1.5px solid var(--bgl-border-color);
|
|
106
115
|
outline-offset: -1px;
|
|
107
116
|
}
|
|
108
117
|
|
|
109
|
-
/* ── underlined: suppress global border-bottom on inner inputs ── */
|
|
110
118
|
.bagel-input.underlined .colorInputPickWrap input {
|
|
111
|
-
border-bottom: none !important;
|
|
112
119
|
border-radius: 0 !important;
|
|
113
120
|
padding-inline: 0.25rem !important;
|
|
114
121
|
}
|
|
115
122
|
|
|
116
|
-
/* ── underlined: bottom border only on the wrap itself ── */
|
|
117
123
|
.bagel-input.underlined .colorInputPickWrap {
|
|
118
124
|
background: transparent !important;
|
|
119
125
|
border-radius: 0 !important;
|
|
@@ -123,7 +129,6 @@ transition: border-color 0.25s ease;
|
|
|
123
129
|
position: relative;
|
|
124
130
|
}
|
|
125
131
|
|
|
126
|
-
/* animated fill line — matches the global underlined ::after pattern */
|
|
127
132
|
.bagel-input.underlined .colorInputPickWrap::after {
|
|
128
133
|
content: '';
|
|
129
134
|
position: absolute;
|
|
@@ -45,6 +45,14 @@ const isDark = ref(false)
|
|
|
45
45
|
*/
|
|
46
46
|
const allowDark = ref(false)
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Whether this project lets the user manually pick a theme. When false (the
|
|
50
|
+
* default), the app always follows the OS ("system") and ignores any saved
|
|
51
|
+
* manual choice — so it updates live with the OS and never gets stuck on a
|
|
52
|
+
* stale dark/light value. When true, a saved manual choice is honored.
|
|
53
|
+
*/
|
|
54
|
+
const manualSelection = ref(false)
|
|
55
|
+
|
|
48
56
|
const isBrowser = typeof window !== 'undefined'
|
|
49
57
|
|
|
50
58
|
function getSystemPrefersDark() {
|
|
@@ -104,14 +112,38 @@ function toggleTheme() {
|
|
|
104
112
|
/**
|
|
105
113
|
* Configure theme behavior for the current app. Call once at startup.
|
|
106
114
|
*
|
|
107
|
-
* @param options.allowDark
|
|
108
|
-
*
|
|
115
|
+
* @param options.allowDark Enable dark mode for this project (default: false).
|
|
116
|
+
* When false, dark / system-dark falls back to light.
|
|
117
|
+
* @param options.manualSelection Whether this project exposes a UI for the user to
|
|
118
|
+
* manually pick a theme (default: false).
|
|
119
|
+
* - false → always follow the OS ("system"); any
|
|
120
|
+
* previously-saved manual choice is ignored, so the
|
|
121
|
+
* app updates live when the OS color scheme changes.
|
|
122
|
+
* - true → honor the user's saved manual choice, and
|
|
123
|
+
* fall back to "system" when they haven't picked one.
|
|
109
124
|
*/
|
|
110
|
-
export function configureTheme(options: { allowDark?: boolean } = {}) {
|
|
125
|
+
export function configureTheme(options: { allowDark?: boolean, manualSelection?: boolean } = {}) {
|
|
111
126
|
if (options.allowDark !== undefined) {
|
|
112
127
|
allowDark.value = options.allowDark
|
|
113
128
|
}
|
|
114
|
-
|
|
129
|
+
if (options.manualSelection !== undefined) {
|
|
130
|
+
manualSelection.value = options.manualSelection
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Register the matchMedia listener + colorMode watcher now, so OS color-scheme
|
|
134
|
+
// changes are picked up live — even if no component ever calls useTheme()
|
|
135
|
+
// (e.g. projects with no manual theme switcher). Without this, "system" mode
|
|
136
|
+
// wouldn't react until something mounted, forcing a refresh.
|
|
137
|
+
initTheme()
|
|
138
|
+
|
|
139
|
+
// When the project has no manual switcher, force "system" — even if initTheme()
|
|
140
|
+
// already ran earlier (via useTheme) and restored a stale saved value before
|
|
141
|
+
// this config was known.
|
|
142
|
+
if (!manualSelection.value) {
|
|
143
|
+
colorMode.value = 'system'
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Re-apply with the new policy so a previously-saved choice is corrected.
|
|
115
147
|
applyTheme(colorMode.value)
|
|
116
148
|
}
|
|
117
149
|
|
|
@@ -152,9 +184,15 @@ function initTheme() {
|
|
|
152
184
|
if (initialized || !isBrowser) { return }
|
|
153
185
|
initialized = true
|
|
154
186
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
187
|
+
// Only restore a saved manual choice when the project allows manual selection.
|
|
188
|
+
// Otherwise always follow the OS, so the app can't get stuck on a stale value.
|
|
189
|
+
if (manualSelection.value) {
|
|
190
|
+
const saved = window.localStorage.getItem(STORAGE_KEY)
|
|
191
|
+
if (themeOptions.value.some(t => t.value === saved)) {
|
|
192
|
+
colorMode.value = saved!
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
colorMode.value = 'system'
|
|
158
196
|
}
|
|
159
197
|
|
|
160
198
|
applyTheme(colorMode.value)
|
|
@@ -166,9 +204,11 @@ function initTheme() {
|
|
|
166
204
|
}
|
|
167
205
|
})
|
|
168
206
|
|
|
169
|
-
// Persist + apply on mode changes
|
|
207
|
+
// Persist + apply on mode changes (persist only matters for manual selection)
|
|
170
208
|
watch(colorMode, (newMode) => {
|
|
171
|
-
|
|
209
|
+
if (manualSelection.value) {
|
|
210
|
+
localStorage.setItem(STORAGE_KEY, newMode)
|
|
211
|
+
}
|
|
172
212
|
applyTheme(newMode)
|
|
173
213
|
})
|
|
174
214
|
}
|
package/src/dialog/Dialog.vue
CHANGED
|
@@ -117,10 +117,10 @@ defineExpose({ close })
|
|
|
117
117
|
<template>
|
|
118
118
|
<dialog
|
|
119
119
|
ref="dialogRef" :class="[positionClass, { 'is-closing': isClosing }]"
|
|
120
|
-
:style="{ '--dialog-width': widthStyle }" class="border-none shadow-30 p-0 testMe1" @click="onBackdropClick"
|
|
120
|
+
:style="{ '--dialog-width': widthStyle }" class="border-none shadow-30 p-0 testMe1 dialog-no-focus-outline" @click="onBackdropClick"
|
|
121
121
|
@cancel="onCancel" @animationend="onAnimationEnd"
|
|
122
122
|
>
|
|
123
|
-
<div class="grid grid-dialog max-height-100-2" @click.stop>
|
|
123
|
+
<div class="grid grid-dialog max-height-100-2" tabindex="-1" autofocus @click.stop>
|
|
124
124
|
<!-- Bottom-sheet grip handle -->
|
|
125
125
|
<div v-if="showGrip" class="dialog-grip" aria-hidden="true" />
|
|
126
126
|
<!-- Header -->
|
|
@@ -199,6 +199,15 @@ max-height: calc(100vh - 2rem);
|
|
|
199
199
|
margin-top: 0.125rem;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
/* The dialog body gets the initial focus (via autofocus, so the close button
|
|
203
|
+
isn't auto-focused). It shouldn't show a focus ring itself. */
|
|
204
|
+
.dialog-no-focus-outline:focus,
|
|
205
|
+
.dialog-no-focus-outline:focus-visible,
|
|
206
|
+
.dialog-no-focus-outline .grid-dialog:focus,
|
|
207
|
+
.dialog-no-focus-outline .grid-dialog:focus-visible {
|
|
208
|
+
outline: none;
|
|
209
|
+
}
|
|
210
|
+
|
|
202
211
|
.overlay-btn {
|
|
203
212
|
opacity: 0;
|
|
204
213
|
animation: fade-in 0.3s ease-out 0.1s forwards;
|
package/src/styles/dark.css
CHANGED
|
@@ -1,35 +1,9 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Activated by useTheme() which toggles the `.bgl-dark-mode` class on <html>.
|
|
5
|
-
*
|
|
6
|
-
* ARCHITECTURE (semantic, NOT inversion):
|
|
7
|
-
* - We do NOT swap --bgl-black / --bgl-white. They keep their real meaning
|
|
8
|
-
* (black = dark, white = light) so colored buttons (.pair-*) that use
|
|
9
|
-
* `color: var(--bgl-white)` stay correct (light text on a colored fill).
|
|
10
|
-
* - Instead we override only the SEMANTIC tokens (surfaces, text, borders)
|
|
11
|
-
* with explicit dark values. Components that consume these tokens
|
|
12
|
-
* (--bgl-bg, --bgl-box-bg, --bgl-text-color, …) become dark automatically.
|
|
13
|
-
*
|
|
14
|
-
* Single source of truth: the dark palette below (--bgl-dm-* raw values), which
|
|
15
|
-
* the semantic tokens reference. If you ever need explicit opt-in dark classes
|
|
16
|
-
* for components that use physical colors, build them on these same tokens.
|
|
17
|
-
* ============================================================================ */
|
|
18
|
-
/* .bgl-dark-mode {
|
|
19
|
-
filter: invert(1);
|
|
20
|
-
}
|
|
1
|
+
/* Dark Mode Theme — .bgl-dark-mode (toggled on <html> by useTheme()).
|
|
2
|
+
Semantic, not inversion: override only the semantic tokens (surfaces, text,
|
|
3
|
+
borders) with dark values; --bgl-black/--bgl-white keep their real meaning. */
|
|
21
4
|
|
|
22
|
-
.bgl-dark-mode
|
|
23
|
-
|
|
24
|
-
.bgl-dark-mode svg,
|
|
25
|
-
.bgl-dark-mode iframe {
|
|
26
|
-
filter: invert(1);
|
|
27
|
-
} */
|
|
28
|
-
|
|
29
|
-
/* `:root.bgl-dark-mode` (the class lives on <html>) raises specificity to
|
|
30
|
-
(0,2,0) so these tokens win over any project that redefines colors in its
|
|
31
|
-
own `:root {}` (e.g. udi sets --bgl-blue: #7ad3f7). The bare .bgl-dark-mode
|
|
32
|
-
is kept as a fallback in case the class is applied to a non-root element. */
|
|
5
|
+
/* `:root.bgl-dark-mode` raises specificity to (0,2,0) so these tokens win over a
|
|
6
|
+
project's own `:root {}`; bare `.bgl-dark-mode` is a non-root fallback. */
|
|
33
7
|
:root.bgl-dark-mode,
|
|
34
8
|
.bgl-dark-mode {
|
|
35
9
|
/* ---- Dark palette (raw values) ---------------------------------------- */
|