@osimart/create-storefront 1.0.25 → 1.0.26
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.
|
@@ -272,6 +272,7 @@
|
|
|
272
272
|
<PhoneNumInput
|
|
273
273
|
v-model="formData.mobile_number"
|
|
274
274
|
variant="bare"
|
|
275
|
+
:themed-popup="true"
|
|
275
276
|
:error="phoneHasError"
|
|
276
277
|
@update="onPhoneUpdate"
|
|
277
278
|
/>
|
|
@@ -375,6 +376,7 @@
|
|
|
375
376
|
@update:model-value="selectCountry($event); clearFieldError('country')"
|
|
376
377
|
placeholder="Country"
|
|
377
378
|
searchable
|
|
379
|
+
themed
|
|
378
380
|
local-search
|
|
379
381
|
full-width
|
|
380
382
|
field="country"
|
|
@@ -408,6 +410,7 @@
|
|
|
408
410
|
@update:model-value="selectZone($event); clearFieldError('zone')"
|
|
409
411
|
placeholder="Zone"
|
|
410
412
|
searchable
|
|
413
|
+
themed
|
|
411
414
|
local-search
|
|
412
415
|
full-width
|
|
413
416
|
field="zone"
|
|
@@ -97,16 +97,20 @@
|
|
|
97
97
|
<div
|
|
98
98
|
v-if="open && !disabled"
|
|
99
99
|
ref="menuRef"
|
|
100
|
-
:style="[floatingStyles, menuWidthStyle, { zIndex: dropdownZIndex }]"
|
|
101
|
-
class="absolute font-poppins
|
|
102
|
-
:class="
|
|
100
|
+
:style="[floatingStyles, menuWidthStyle, themeVars, { zIndex: dropdownZIndex }]"
|
|
101
|
+
class="absolute font-poppins border rounded-md shadow-lg max-h-60 overflow-auto dropdown-select-popup"
|
|
102
|
+
:class="[
|
|
103
|
+
dropdownWidth ? '' : 'w-max max-w-xs',
|
|
104
|
+
themed ? 'dropdown-select-popup--themed' : 'bg-white border-gray-300',
|
|
105
|
+
]"
|
|
103
106
|
@scroll.passive="onScroll"
|
|
104
107
|
>
|
|
105
108
|
<!-- Search -->
|
|
106
109
|
<div v-if="searchable" class="p-2">
|
|
107
110
|
<input
|
|
108
111
|
v-model="searchQuery"
|
|
109
|
-
class="
|
|
112
|
+
class="w-full border px-2 py-1 rounded text-sm focus:outline-none"
|
|
113
|
+
:class="themed ? 'dd-search' : 'bg-input'"
|
|
110
114
|
placeholder="Search..."
|
|
111
115
|
/>
|
|
112
116
|
</div>
|
|
@@ -116,7 +120,8 @@
|
|
|
116
120
|
v-for="opt in filteredOptions"
|
|
117
121
|
:key="opt.value"
|
|
118
122
|
:style="{ color: opt.color }"
|
|
119
|
-
class="px-4 py-2 flex justify-between items-center
|
|
123
|
+
class="px-4 py-2 flex justify-between items-center cursor-pointer"
|
|
124
|
+
:class="themed ? 'dd-option' : 'hover:bg-gray-100'"
|
|
120
125
|
@click="toggleOption(opt.value)"
|
|
121
126
|
>
|
|
122
127
|
<div class="flex items-center gap-2 min-w-0">
|
|
@@ -141,7 +146,7 @@
|
|
|
141
146
|
</li>
|
|
142
147
|
</ul>
|
|
143
148
|
|
|
144
|
-
<div v-else-if="!loading" class="px-4 py-2 text-fifthosiblue text-center text-sm">
|
|
149
|
+
<div v-else-if="!loading" class="px-4 py-2 text-fifthosiblue text-center text-sm" :class="{ 'dd-empty': themed }">
|
|
145
150
|
No results
|
|
146
151
|
</div>
|
|
147
152
|
|
|
@@ -193,6 +198,11 @@ const props = defineProps({
|
|
|
193
198
|
// Explicit width for the dropdown menu (any valid CSS width, e.g. '320px',
|
|
194
199
|
// '24rem', '100%'). Overrides the default w-max/max-w-xs/minWidth-match behavior.
|
|
195
200
|
dropdownWidth: { type: String, default: null },
|
|
201
|
+
// Opt-in: the popup takes its colours from the storefront theme variables
|
|
202
|
+
// (the same ones the form fields use) instead of the hardcoded white/gray.
|
|
203
|
+
// The menu is teleported to <body>, so the variables are copied from the
|
|
204
|
+
// trigger's element when it opens. Off = every existing usage is unchanged.
|
|
205
|
+
themed: { type: Boolean, default: false },
|
|
196
206
|
});
|
|
197
207
|
const parentModalZIndex = inject("modalZIndex", null);
|
|
198
208
|
const dropdownZIndex = computed(() =>
|
|
@@ -211,6 +221,38 @@ const rootRef = ref(null);
|
|
|
211
221
|
const triggerBtnRef = ref(null);
|
|
212
222
|
const triggerWidth = ref(0);
|
|
213
223
|
|
|
224
|
+
// CSS variables the themed popup needs. The teleported menu sits outside the
|
|
225
|
+
// element that defines them, so they're read from the trigger when it opens.
|
|
226
|
+
// Names match osi-controls.css: the Inputs theme group (--osi-input-*) and the
|
|
227
|
+
// colour scheme (--osi-bg / --osi-text / --osi-border).
|
|
228
|
+
const THEME_VARS = [
|
|
229
|
+
"--osi-bg",
|
|
230
|
+
"--osi-text",
|
|
231
|
+
"--osi-border",
|
|
232
|
+
"--osi-input-bg",
|
|
233
|
+
"--osi-input-fg",
|
|
234
|
+
"--osi-input-border-color",
|
|
235
|
+
// The checkout's card colours (set inline on .osi-ck, so only present there).
|
|
236
|
+
"--ck-card-bg",
|
|
237
|
+
"--ck-card-text",
|
|
238
|
+
"--ck-card-border",
|
|
239
|
+
];
|
|
240
|
+
const themeVars = ref({});
|
|
241
|
+
|
|
242
|
+
function readThemeVars() {
|
|
243
|
+
if (!props.themed || !rootRef.value) {
|
|
244
|
+
themeVars.value = {};
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const cs = getComputedStyle(rootRef.value);
|
|
248
|
+
const vars = {};
|
|
249
|
+
for (const name of THEME_VARS) {
|
|
250
|
+
const value = cs.getPropertyValue(name).trim();
|
|
251
|
+
if (value) vars[name] = value;
|
|
252
|
+
}
|
|
253
|
+
themeVars.value = vars;
|
|
254
|
+
}
|
|
255
|
+
|
|
214
256
|
const menuWidthStyle = computed(() => {
|
|
215
257
|
if (props.dropdownWidth) return { width: props.dropdownWidth };
|
|
216
258
|
if (!props.autoWidth) return { minWidth: triggerWidth.value + 'px' };
|
|
@@ -410,6 +452,7 @@ watch(open, (isOpen) => {
|
|
|
410
452
|
if (isOpen) {
|
|
411
453
|
eventBus.emit("dropdown:opened", instanceId);
|
|
412
454
|
triggerWidth.value = rootRef.value ? rootRef.value.offsetWidth : 0;
|
|
455
|
+
readThemeVars();
|
|
413
456
|
document.addEventListener("mousedown", handleDocumentClick, true);
|
|
414
457
|
emit("open");
|
|
415
458
|
} else {
|
|
@@ -429,4 +472,30 @@ onBeforeUnmount(() => {
|
|
|
429
472
|
onUnmounted(() => {
|
|
430
473
|
eventBus.off("dropdown:opened", onGlobalDropdownOpened);
|
|
431
474
|
});
|
|
432
|
-
</script>
|
|
475
|
+
</script>
|
|
476
|
+
|
|
477
|
+
<style scoped>
|
|
478
|
+
/* Only applied when the `themed` prop is set. Every colour falls back to the
|
|
479
|
+
old hardcoded one, so a themed popup outside the storefront still looks
|
|
480
|
+
the same as before. */
|
|
481
|
+
.dropdown-select-popup--themed {
|
|
482
|
+
background: var(--osi-input-bg, var(--ck-card-bg, var(--osi-bg, #fff)));
|
|
483
|
+
color: var(--osi-input-fg, var(--ck-card-text, var(--osi-text, inherit)));
|
|
484
|
+
border-color: var(--osi-input-border-color, var(--ck-card-border, var(--osi-border, #d1d5db)));
|
|
485
|
+
}
|
|
486
|
+
.dropdown-select-popup--themed .dd-option:hover {
|
|
487
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
488
|
+
}
|
|
489
|
+
.dropdown-select-popup--themed .dd-search {
|
|
490
|
+
background: transparent;
|
|
491
|
+
color: inherit;
|
|
492
|
+
border-color: color-mix(in srgb, currentColor 20%, transparent);
|
|
493
|
+
}
|
|
494
|
+
.dropdown-select-popup--themed .dd-search::placeholder {
|
|
495
|
+
color: color-mix(in srgb, currentColor 50%, transparent);
|
|
496
|
+
}
|
|
497
|
+
.dropdown-select-popup--themed .dd-empty {
|
|
498
|
+
color: inherit;
|
|
499
|
+
opacity: 0.6;
|
|
500
|
+
}
|
|
501
|
+
</style>
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
:searchable="true"
|
|
15
15
|
:local-search="true"
|
|
16
16
|
smallText
|
|
17
|
+
themed
|
|
17
18
|
@search="onSearch"
|
|
18
19
|
@update:modelValue="onCountryChange"
|
|
19
20
|
@open="isFocused = true"
|
|
@@ -64,7 +65,8 @@
|
|
|
64
65
|
v-else
|
|
65
66
|
class="w-full"
|
|
66
67
|
:class="[
|
|
67
|
-
effectiveVariant === 'underline' ? 'font-thoren relative' : 'font-poppins'
|
|
68
|
+
effectiveVariant === 'underline' ? 'font-thoren relative' : 'font-poppins',
|
|
69
|
+
{ 'phone-input-themed': themedPopup && effectiveVariant === 'bare' }
|
|
68
70
|
]"
|
|
69
71
|
>
|
|
70
72
|
<label
|
|
@@ -100,6 +102,7 @@
|
|
|
100
102
|
@update:modelValue="onCountryChange"
|
|
101
103
|
@open="isFocused = true"
|
|
102
104
|
@close="isFocused = false"
|
|
105
|
+
:themed="themedPopup"
|
|
103
106
|
:fullWidth="false"
|
|
104
107
|
class="shrink min-w-[90px]"
|
|
105
108
|
:class="ispopup ? 'lg:min-w-[70px]':'lg:min-w-[140px]'"
|
|
@@ -196,6 +199,9 @@ const props = defineProps({
|
|
|
196
199
|
inputClass: { type: [String, Array, Object], default: 'osi-input' },
|
|
197
200
|
inputId: { type: String, default: '' },
|
|
198
201
|
disabled: { type: Boolean, default: false },
|
|
202
|
+
// Non-theme variants only: opt the country popup into the theme colours.
|
|
203
|
+
// (The `theme` variant is always themed.)
|
|
204
|
+
themedPopup: { type: Boolean, default: false },
|
|
199
205
|
})
|
|
200
206
|
|
|
201
207
|
const emit = defineEmits(['update:modelValue', 'update', 'clear-error'])
|
|
@@ -431,4 +437,20 @@ const getFlagUrl = (code) => {
|
|
|
431
437
|
outline: none !important;
|
|
432
438
|
box-shadow: none !important;
|
|
433
439
|
}
|
|
434
|
-
|
|
440
|
+
|
|
441
|
+
/* Keep the compact bare layout while using the shared Inputs color tokens. */
|
|
442
|
+
.phone-input-themed .dropdown-trigger-btn,
|
|
443
|
+
.phone-input-themed .text-input {
|
|
444
|
+
color: var(--osi-input-fg, inherit);
|
|
445
|
+
}
|
|
446
|
+
.phone-input-themed .text-input {
|
|
447
|
+
background-color: var(--osi-input-bg, transparent);
|
|
448
|
+
}
|
|
449
|
+
.phone-input-themed .text-input::placeholder {
|
|
450
|
+
color: var(--osi-input-placeholder, currentColor);
|
|
451
|
+
opacity: 1;
|
|
452
|
+
}
|
|
453
|
+
.phone-input-themed .border-r {
|
|
454
|
+
border-color: var(--osi-input-border-color, #e5e7eb);
|
|
455
|
+
}
|
|
456
|
+
</style>
|
|
@@ -146,6 +146,8 @@ export default function useLogic() {
|
|
|
146
146
|
if (s.HEADER_ICON_BORDER) style["--osi-header-icon-border"] = s.HEADER_ICON_BORDER;
|
|
147
147
|
if (s.HEADER_CART_BADGE_BG) style["--osi-header-badge-bg"] = s.HEADER_CART_BADGE_BG;
|
|
148
148
|
if (s.HEADER_CART_BADGE_TEXT) style["--osi-header-badge-text"] = s.HEADER_CART_BADGE_TEXT;
|
|
149
|
+
if (s.HEADER_BORDER_COLOR) style["--osi-header-border"] = s.HEADER_BORDER_COLOR;
|
|
150
|
+
if (s.HEADER_BORDER_WIDTH) style["--osi-header-border-w"] = `${s.HEADER_BORDER_WIDTH}px`;
|
|
149
151
|
style["--osi-header-pad-y"] = `${s.HEADER_PADDING_Y}px`;
|
|
150
152
|
// Side padding lives on the header itself, not on the inner box — see the
|
|
151
153
|
// note on .osi-header-inner below. 16 is COMMON_STYLE_SETTINGS' PADDING_X
|
package/package.json
CHANGED