@bagelink/vue 1.15.331 → 1.15.333

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.331",
4
+ "version": "1.15.333",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -17,6 +17,9 @@ const props = withDefaults(defineProps<{
17
17
  (theme name → `pair-*`, or a raw CSS color) and contrasts the glyph.
18
18
  Without `color`, just the circular shape. */
19
19
  round?: boolean
20
+ /** Soft circular chip: light tinted background + full-color glyph and border.
21
+ Uses `color`, and defaults to black when no color is provided. */
22
+ soft?: boolean
20
23
  weight?: number | string
21
24
  fontAwesome?: boolean
22
25
  fill?: boolean
@@ -159,12 +162,16 @@ const isRawCssColor = computed(() => {
159
162
  || /^(rgb|hsl|hwb|lab|lch|oklch|color)\(/i.test(c)
160
163
  })
161
164
 
165
+ const hasChip = computed(() => props.round || props.soft)
166
+
162
167
  const roundPairClass = computed(() => {
163
- if (!props.round || !props.color || isRawCssColor.value) { return undefined }
164
- return `pair-${props.color}`
168
+ if (!hasChip.value || isRawCssColor.value) { return undefined }
169
+ if (props.color) { return `pair-${props.color}` }
170
+ return props.soft ? 'pair-black' : undefined
165
171
  })
166
172
 
167
- const roundClass = computed(() => (props.round ? 'bgl_icon-round' : undefined))
173
+ const roundClass = computed(() => (hasChip.value ? 'bgl_icon-round' : undefined))
174
+ const softClass = computed(() => (props.soft ? 'soft' : undefined))
168
175
 
169
176
  const iconStyle = computed(() => {
170
177
  const style: Record<string, string> = {
@@ -177,11 +184,17 @@ const iconStyle = computed(() => {
177
184
  } else {
178
185
  style['font-variation-settings'] = `'wght' ${props.weight || 400}`
179
186
  }
180
- if (props.round) {
187
+ if (hasChip.value) {
181
188
  style.width = `calc(${computedSize.value}rem * 2)`
182
189
  style.height = `calc(${computedSize.value}rem * 2)`
183
190
  if (isRawCssColor.value && props.color) {
184
- style.backgroundColor = props.color
191
+ if (props.soft) {
192
+ style.backgroundColor = `color-mix(in srgb, ${props.color} 18%, transparent)`
193
+ style.color = props.color
194
+ style.border = `1px solid ${props.color}`
195
+ } else {
196
+ style.backgroundColor = props.color
197
+ }
185
198
  }
186
199
  } else if (props.color) {
187
200
  style.color = props.color
@@ -193,23 +206,24 @@ const iconStyle = computed(() => {
193
206
  <template>
194
207
  <Transition :name="transitionName" mode="out-in">
195
208
  <span
196
- v-if="iconRenderType === 'material'" :key="iconRender" class="bgl_icon-font notranslate"
197
- :class="[animateClass, roundClass, roundPairClass, { 'color-white keep-white': round && isRawCssColor }]"
209
+ v-if="iconRenderType === 'material'" :key="`material-${iconRender}`" class="bgl_icon-font notranslate"
210
+ :class="[animateClass, roundClass, roundPairClass, softClass, { 'color-white keep-white': round && !soft && isRawCssColor }]"
198
211
  :style="iconStyle" translate="no"
199
212
  >
200
213
  {{ iconRender }}
201
214
  </span>
202
215
  <span
203
- v-else-if="iconRenderType === 'font-awesome'" :key="iconRender" class="fa bgl_icon-font notranslate" :class="[
216
+ v-else-if="iconRenderType === 'font-awesome'" :key="`font-awesome-${iconRender}`" class="fa bgl_icon-font notranslate" :class="[
204
217
  `fa-${iconRender}`,
205
218
  animateClass,
206
219
  roundClass,
207
220
  roundPairClass,
221
+ softClass,
208
222
  {
209
223
  'fa-brands': isFaBrand,
210
224
  'fa-solid': fill,
211
225
  'far': !fill && !isFaBrand,
212
- 'color-white keep-white': round && isRawCssColor,
226
+ 'color-white keep-white': round && !soft && isRawCssColor,
213
227
  },
214
228
  ]" :style="iconStyle"
215
229
  translate="no"
@@ -230,7 +230,10 @@ function updateField(key: string, value: any, field: FieldBuilder) {
230
230
  }
231
231
 
232
232
  function isFieldEmpty(value: any, field: FieldBuilder): boolean {
233
- return value == null || value === '' || value === false
233
+ // `false` is a valid answer for boolean radio/toggle fields (for example a
234
+ // required Yes/No question). Only an unchecked checkbox uses false as its
235
+ // empty state.
236
+ return value == null || value === '' || (value === false && field._type === 'checkbox')
234
237
  || (Array.isArray(value) && value.length === 0)
235
238
  || (field._type === 'tel' && typeof value === 'string' && /^\+\d+$/.test(value))
236
239
  }
@@ -445,6 +448,7 @@ async function handleSubmit(event?: Event): Promise<boolean> {
445
448
 
446
449
  if (!isValid) {
447
450
  event?.stopPropagation()
451
+ formElement.value?.reportValidity()
448
452
 
449
453
  const firstErrorKey = visibleFields.value.find(({ key }) => validationErrors.value[key])?.key
450
454
 
package/src/i18n/index.ts CHANGED
@@ -19,6 +19,34 @@ const bagelinkLocales = {
19
19
  ru,
20
20
  } as const
21
21
 
22
+ function mergeMessages(
23
+ base: Record<string, unknown>,
24
+ overrides: Record<string, unknown>,
25
+ ): Record<string, unknown> {
26
+ const merged = { ...base }
27
+
28
+ for (const [key, value] of Object.entries(overrides)) {
29
+ const baseValue = merged[key]
30
+ if (
31
+ baseValue != null
32
+ && value != null
33
+ && typeof baseValue === 'object'
34
+ && typeof value === 'object'
35
+ && !Array.isArray(baseValue)
36
+ && !Array.isArray(value)
37
+ ) {
38
+ merged[key] = mergeMessages(
39
+ baseValue as Record<string, unknown>,
40
+ value as Record<string, unknown>,
41
+ )
42
+ } else {
43
+ merged[key] = value
44
+ }
45
+ }
46
+
47
+ return merged
48
+ }
49
+
22
50
  export interface CreateBagelI18nOptions {
23
51
  /** Active locale (default: 'en'). Same as vue-i18n's `locale`. */
24
52
  locale?: string
@@ -46,10 +74,10 @@ export function createI18n(options: CreateBagelI18nOptions = {}): I18n {
46
74
  const mergedMessages: Record<string, Record<string, unknown>> = {}
47
75
 
48
76
  for (const lang of supportedLocales) {
49
- mergedMessages[lang] = {
50
- ...(bagelinkLocales[lang as keyof typeof bagelinkLocales] || {}),
51
- ...(messages[lang] || {}),
52
- }
77
+ mergedMessages[lang] = mergeMessages(
78
+ bagelinkLocales[lang as keyof typeof bagelinkLocales] || {},
79
+ messages[lang] || {},
80
+ )
53
81
  }
54
82
 
55
83
  // Also include any user-provided locales not in bagelink's built-ins