11<script setup>
2- import { computed , useTemplateRef , watch , ref , inject } from ' vue' ;
2+ import { computed , onMounted , onUnmounted , useTemplateRef , watch , ref , inject } from ' vue' ;
33import { injectContainerContext } from ' ./Container.vue' ;
44import { injectFieldsContext } from ' ./FieldsProvider.vue' ;
55import {
@@ -112,11 +112,14 @@ watch(
112112);
113113
114114function focused () {
115- // todo
115+ if (fieldPathPrefix .value ) return ;
116+ Statamic .$events .$emit (' field:focused' , { containerName: container .name .value , handle });
116117}
117118
118- function blurred () {
119- // todo
119+ function blurred (event ) {
120+ if (fieldPathPrefix .value ) return ;
121+ if (event ? .currentTarget ? .contains (event .relatedTarget )) return ;
122+ Statamic .$events .$emit (' field:blurred' , { containerName: container .name .value , handle });
120123}
121124
122125const values = computed (() => {
@@ -169,7 +172,30 @@ const isReadOnly = computed(() => {
169172 return isLocked .value || props .config .visibility === ' read_only' || false ;
170173});
171174
172- const isLocked = computed (() => false ); // todo
175+ const lockedBy = ref (null );
176+ const isLocked = computed (() => lockedBy .value !== null && lockedBy .value .id !== Statamic .user .id );
177+
178+ function _onFieldLock ({ containerName, handle: lockedHandle, user }) {
179+ if (containerName === container .name .value && lockedHandle === handle) {
180+ lockedBy .value = user;
181+ }
182+ }
183+ function _onFieldUnlock ({ containerName, handle: unlockedHandle }) {
184+ if (containerName === container .name .value && unlockedHandle === handle) {
185+ lockedBy .value = null ;
186+ }
187+ }
188+
189+ onMounted (() => {
190+ Statamic .$events .$on (' field:lock' , _onFieldLock);
191+ Statamic .$events .$on (' field:unlock' , _onFieldUnlock);
192+ });
193+
194+ onUnmounted (() => {
195+ Statamic .$events .$off (' field:lock' , _onFieldLock);
196+ Statamic .$events .$off (' field:unlock' , _onFieldUnlock);
197+ });
198+
173199
174200const isSyncable = computed (() => {
175201 // Only top-level fields can be synced.
@@ -239,6 +265,7 @@ const fieldtypeComponentEvents = computed(() => ({
239265 {{ __ (config .display ) }}
240266 < / span>
241267 < / template>
268+ < ui- avatar v- if = " isLocked" : user= " lockedBy" class = " rounded-full w-4 h-4 text-2xs" v- tooltip= " lockedBy.name" / >
242269 < ui- button size= " xs" inset icon= " synced" variant= " ghost" v- tooltip= " __('messages.field_synced_with_origin')" v- if = " !isReadOnly && isSyncable" v- show= " isSynced" @click= " desync" / >
243270 < ui- button size= " xs" inset icon= " unsynced" variant= " ghost" v- tooltip= " __('messages.field_desynced_from_origin')" v- if = " !isReadOnly && isSyncable" v- show= " !isSynced" @click= " sync" / >
244271 < / Label>
@@ -249,7 +276,7 @@ const fieldtypeComponentEvents = computed(() => ({
249276 < div class = " text-xs text-red-600" v- if = " !fieldtypeComponentExists" >
250277 Component < code v- text= " fieldtypeComponent" >< / code> does not exist.
251278 < / div>
252- < div : dir= " direction" >
279+ < div : dir= " direction" @focusin = " focused " @focusout = " blurred " : class = " { 'pointer-events-none select-none': isLocked } " >
253280 < Component
254281 ref= " fieldtype"
255282 : is= " fieldtypeComponent"
0 commit comments