@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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "1.15.102",
4
+ "version": "1.15.106",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -51,12 +51,12 @@ watch(
51
51
  }"
52
52
  >
53
53
  <input
54
- :id="id" v-model="inputVal" class="border" type="color" :placeholder="resolveI18n(placeholder) || resolveI18n(label)"
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 border colorInputPick" type="text"
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 Enable dark mode for this project (default: false).
108
- * When false, dark / system-dark falls back to light.
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
- // Re-apply with the new policy so a previously-saved dark choice is corrected.
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
- const saved = window.localStorage.getItem(STORAGE_KEY)
156
- if (themeOptions.value.some(t => t.value === saved)) {
157
- colorMode.value = saved!
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
- localStorage.setItem(STORAGE_KEY, newMode)
209
+ if (manualSelection.value) {
210
+ localStorage.setItem(STORAGE_KEY, newMode)
211
+ }
172
212
  applyTheme(newMode)
173
213
  })
174
214
  }
@@ -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;
@@ -1,35 +1,9 @@
1
- /* ============================================================================
2
- * Dark Mode Theme — .bgl-dark-mode
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 img,
23
- .bgl-dark-mode video,
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) ---------------------------------------- */