sanity-plugin-internationalized-array 1.10.0 → 1.10.2
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/README.md +1 -1
- package/lib/index.esm.js +7 -5
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +6 -4
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/InternationalizedArray.tsx +29 -15
- package/src/fieldActions/index.ts +1 -1
- package/src/utils/flattenSchemaType.ts +7 -9
package/lib/index.js
CHANGED
|
@@ -9473,10 +9473,12 @@ addLanguageKeys.map(id=>({...itemBase,_key:id})):// Or one for every missing lan
|
|
|
9473
9473
|
filteredLanguages.filter(language=>(value==null?void 0:value.length)?!value.find(v=>v._key===language.id):true).map(language=>({...itemBase,_key:language.id}));const languagesInUse=(value==null?void 0:value.length)?value.map(v=>v):[];const insertions=newItems.map(item=>{const languageIndex=languages.findIndex(l=>item._key===l.id);const remainingLanguages=languages.slice(languageIndex+1);const nextLanguageIndex=languagesInUse.findIndex(l=>// eslint-disable-next-line max-nested-callbacks
|
|
9474
9474
|
remainingLanguages.find(r=>r.id===l._key));if(nextLanguageIndex<0){languagesInUse.push(item);}else{languagesInUse.splice(nextLanguageIndex,0,item);}return nextLanguageIndex<0?// No next language (-1), add to end of array
|
|
9475
9475
|
sanity.insert([item],"after",[...path,nextLanguageIndex]):// Next language found, insert before that
|
|
9476
|
-
sanity.insert([item],"before",[...path,nextLanguageIndex]);});return insertions;}const createTranslateFieldActions=(fieldActionProps,_ref)=>{let{languages,filteredLanguages}=_ref;return languages.map(language=>{const value=sanity.useFormValue(fieldActionProps.path);const disabled=value&&Array.isArray(value)?Boolean(value==null?void 0:value.find(item=>item._key===language.id)):false;const hidden=!filteredLanguages.some(f=>f.id===language.id);const{onChange}=desk.useDocumentPane();const onAction=react.useCallback(()=>{const{schemaType,path}=fieldActionProps;const addLanguageKeys=[language.id];const patches=createAddLanguagePatches({addLanguageKeys,schemaType,languages,filteredLanguages,value,path});onChange(sanity.PatchEvent.from([sanity.setIfMissing([],path),...patches]));},[language.id,value,onChange]);return{type:"action",icon:icons.AddIcon,onAction,title:language.
|
|
9476
|
+
sanity.insert([item],"before",[...path,nextLanguageIndex]);});return insertions;}const createTranslateFieldActions=(fieldActionProps,_ref)=>{let{languages,filteredLanguages}=_ref;return languages.map(language=>{const value=sanity.useFormValue(fieldActionProps.path);const disabled=value&&Array.isArray(value)?Boolean(value==null?void 0:value.find(item=>item._key===language.id)):false;const hidden=!filteredLanguages.some(f=>f.id===language.id);const{onChange}=desk.useDocumentPane();const onAction=react.useCallback(()=>{const{schemaType,path}=fieldActionProps;const addLanguageKeys=[language.id];const patches=createAddLanguagePatches({addLanguageKeys,schemaType,languages,filteredLanguages,value,path});onChange(sanity.PatchEvent.from([sanity.setIfMissing([],path),...patches]));},[language.id,value,onChange]);return{type:"action",icon:icons.AddIcon,onAction,title:language.title,hidden,disabled};});};const AddMissingTranslationsFieldAction=(fieldActionProps,_ref2)=>{let{languages,filteredLanguages}=_ref2;const value=sanity.useFormValue(fieldActionProps.path);const disabled=value&&value.length===filteredLanguages.length;const hidden=checkAllLanguagesArePresent(filteredLanguages,value);const{onChange}=desk.useDocumentPane();const onAction=react.useCallback(()=>{const{schemaType,path}=fieldActionProps;const addLanguageKeys=[];const patches=createAddLanguagePatches({addLanguageKeys,schemaType,languages,filteredLanguages,value,path});onChange(sanity.PatchEvent.from([sanity.setIfMissing([],path),...patches]));},[fieldActionProps,filteredLanguages,languages,onChange,value]);return{type:"action",icon:icons.AddIcon,onAction,title:createAddAllTitle(value,filteredLanguages),disabled,hidden};};const internationalizedArrayFieldAction=sanity.defineDocumentFieldAction({name:"internationalizedArray",useAction(fieldActionProps){var _a,_b;const isInternationalizedArrayField=(_b=(_a=fieldActionProps==null?void 0:fieldActionProps.schemaType)==null?void 0:_a.type)==null?void 0:_b.name.startsWith("internationalizedArray");const{languages,filteredLanguages}=useInternationalizedArrayContext();const translateFieldActions=createTranslateFieldActions(fieldActionProps,{languages,filteredLanguages});return{type:"group",icon:icons.TranslateIcon,title:"Add Translation",renderAsButton:true,children:isInternationalizedArrayField?[...translateFieldActions,AddMissingTranslationsFieldAction(fieldActionProps,{languages,filteredLanguages})]:[],hidden:!isInternationalizedArrayField};}});function camelCase(string){return string.replace(/-([a-z])/g,g=>g[1].toUpperCase());}function titleCase(string){return string.split(" ").map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join(" ");}function pascalCase(string){return titleCase(camelCase(string));}function createFieldName(name){let addValue=arguments.length>1&&arguments[1]!==undefined?arguments[1]:false;return addValue?["internationalizedArray",pascalCase(name),"Value"].join(""):["internationalizedArray",pascalCase(name)].join("");}const schemaExample={languages:[{id:"en",title:"English"},{id:"no",title:"Norsk"}]};function Feedback(){return/* @__PURE__ */jsxRuntime.jsx(ui.Card,{tone:"caution",border:true,radius:2,padding:3,children:/* @__PURE__ */jsxRuntime.jsxs(ui.Stack,{space:4,children:[/* @__PURE__ */jsxRuntime.jsxs(ui.Text,{children:["An array of language objects must be passed into the"," ",/* @__PURE__ */jsxRuntime.jsx("code",{children:"internationalizedArray"})," helper function, each with an"," ",/* @__PURE__ */jsxRuntime.jsx("code",{children:"id"})," and ",/* @__PURE__ */jsxRuntime.jsx("code",{children:"title"})," field. Example:"]}),/* @__PURE__ */jsxRuntime.jsx(ui.Card,{padding:2,border:true,radius:2,children:/* @__PURE__ */jsxRuntime.jsx(ui.Code,{size:1,language:"javascript",children:JSON.stringify(schemaExample,null,2)})})]})});}function InternationalizedArray(props){const{members,value,schemaType,onChange}=props;const readOnly=typeof schemaType.readOnly==="boolean"?schemaType.readOnly:false;const toast=ui.useToast();const{languages,filteredLanguages,defaultLanguages,buttonAddAll,buttonLocations}=useInternationalizedArrayContext();const{selectedLanguageIds,options:languageFilterOptions}=languageFilter.useLanguageFilterStudioContext();const documentType=sanity.useFormValue(["_type"]);const languageFilterEnabled=typeof documentType==="string"&&languageFilterOptions.documentTypes.includes(documentType);const filteredMembers=react.useMemo(()=>languageFilterEnabled?members.filter(member=>{if(member.kind!=="item"){return false;}const valueMember=member.item.members[0];if(valueMember.kind!=="field"){return false;}return languageFilterOptions.filterField(member.item.schemaType,valueMember,selectedLanguageIds);}):members,[languageFilterEnabled,members,languageFilterOptions,selectedLanguageIds]);const handleAddLanguage=react.useCallback(param=>{var _a;if(!(filteredLanguages==null?void 0:filteredLanguages.length)){return;}const addLanguageKeys=Array.isArray(param)?param:[(_a=param==null?void 0:param.currentTarget)==null?void 0:_a.value].filter(Boolean);const patches=createAddLanguagePatches({addLanguageKeys,schemaType,languages,filteredLanguages,value});onChange([sanity.setIfMissing([]),...patches]);},[filteredLanguages,languages,onChange,schemaType,value]);const documentCreatedAt=sanity.useFormValue(["_createdAt"]);const[hasAddedDefaultLanguages,setHasAddedDefaultLanguages]=react.useState(false);react.useEffect(()=>{if(// Hasn't already added default languages
|
|
9477
|
+
// (This prevents the document being recreated when deleted)
|
|
9478
|
+
!hasAddedDefaultLanguages&&// This array field is empty
|
|
9477
9479
|
!value&&// Document form is in "not yet created" state
|
|
9478
9480
|
!documentCreatedAt&&// Plugin config included default languages
|
|
9479
|
-
defaultLanguages&&(defaultLanguages==null?void 0:defaultLanguages.length)>0){handleAddLanguage(defaultLanguages);}const handleRestoreOrder=react.useCallback(()=>{if(!(value==null?void 0:value.length)||!(languages==null?void 0:languages.length)){return;}const updatedValue=value.reduce((acc,v)=>{const newIndex=languages.findIndex(l=>l.id===(v==null?void 0:v._key));if(newIndex>-1){acc[newIndex]=v;}return acc;},[]).filter(Boolean);if((value==null?void 0:value.length)!==updatedValue.length){toast.push({title:"There was an error reordering languages",status:"warning"});}onChange(sanity.set(updatedValue));},[toast,languages,onChange,value]);const allKeysAreLanguages=react.useMemo(()=>{if(!(value==null?void 0:value.length)||!(languages==null?void 0:languages.length)){return true;}return value==null?void 0:value.every(v=>languages.find(l=>(l==null?void 0:l.id)===(v==null?void 0:v._key)));},[value,languages]);const languagesInUse=react.useMemo(()=>languages&&languages.length>1?languages.filter(l=>value==null?void 0:value.find(v=>v._key===l.id)):[],[languages,value]);const languagesOutOfOrder=react.useMemo(()=>{if(!(value==null?void 0:value.length)||!languagesInUse.length){return[];}return value.map((v,vIndex)=>vIndex===languagesInUse.findIndex(l=>l.id===v._key)?null:v).filter(Boolean);},[value,languagesInUse]);const languagesAreValid=react.useMemo(()=>!(languages==null?void 0:languages.length)||(languages==null?void 0:languages.length)&&languages.every(item=>item.id&&item.title),[languages]);react.useEffect(()=>{if(languagesOutOfOrder.length>0&&allKeysAreLanguages){handleRestoreOrder();}},[languagesOutOfOrder,allKeysAreLanguages,handleRestoreOrder]);const allLanguagesArePresent=react.useMemo(()=>checkAllLanguagesArePresent(filteredLanguages,value),[filteredLanguages,value]);if(!languagesAreValid){return/* @__PURE__ */jsxRuntime.jsx(Feedback,{});}const addButtonsAreVisible=// Plugin was configured to display buttons here (default!)
|
|
9481
|
+
defaultLanguages&&(defaultLanguages==null?void 0:defaultLanguages.length)>0){handleAddLanguage(defaultLanguages);setHasAddedDefaultLanguages(true);}},[defaultLanguages,documentCreatedAt,handleAddLanguage,hasAddedDefaultLanguages,value]);const handleRestoreOrder=react.useCallback(()=>{if(!(value==null?void 0:value.length)||!(languages==null?void 0:languages.length)){return;}const updatedValue=value.reduce((acc,v)=>{const newIndex=languages.findIndex(l=>l.id===(v==null?void 0:v._key));if(newIndex>-1){acc[newIndex]=v;}return acc;},[]).filter(Boolean);if((value==null?void 0:value.length)!==updatedValue.length){toast.push({title:"There was an error reordering languages",status:"warning"});}onChange(sanity.set(updatedValue));},[toast,languages,onChange,value]);const allKeysAreLanguages=react.useMemo(()=>{if(!(value==null?void 0:value.length)||!(languages==null?void 0:languages.length)){return true;}return value==null?void 0:value.every(v=>languages.find(l=>(l==null?void 0:l.id)===(v==null?void 0:v._key)));},[value,languages]);const languagesInUse=react.useMemo(()=>languages&&languages.length>1?languages.filter(l=>value==null?void 0:value.find(v=>v._key===l.id)):[],[languages,value]);const languagesOutOfOrder=react.useMemo(()=>{if(!(value==null?void 0:value.length)||!languagesInUse.length){return[];}return value.map((v,vIndex)=>vIndex===languagesInUse.findIndex(l=>l.id===v._key)?null:v).filter(Boolean);},[value,languagesInUse]);const languagesAreValid=react.useMemo(()=>!(languages==null?void 0:languages.length)||(languages==null?void 0:languages.length)&&languages.every(item=>item.id&&item.title),[languages]);react.useEffect(()=>{if(languagesOutOfOrder.length>0&&allKeysAreLanguages){handleRestoreOrder();}},[languagesOutOfOrder,allKeysAreLanguages,handleRestoreOrder]);const allLanguagesArePresent=react.useMemo(()=>checkAllLanguagesArePresent(filteredLanguages,value),[filteredLanguages,value]);if(!languagesAreValid){return/* @__PURE__ */jsxRuntime.jsx(Feedback,{});}const addButtonsAreVisible=// Plugin was configured to display buttons here (default!)
|
|
9480
9482
|
buttonLocations.includes("field")&&// There's at least one language visible
|
|
9481
9483
|
(filteredLanguages==null?void 0:filteredLanguages.length)>0&&// Not every language has a value yet
|
|
9482
9484
|
!allLanguagesArePresent;const fieldHasMembers=(members==null?void 0:members.length)>0;return/* @__PURE__ */jsxRuntime.jsxs(ui.Stack,{space:2,children:[fieldHasMembers?/* @__PURE__ */jsxRuntime.jsx(jsxRuntime.Fragment,{children:filteredMembers.map(member=>{if(member.kind==="item"){return/* @__PURE__ */react.createElement(sanity.ArrayOfObjectsItem,{...props,key:member.key,member});}return/* @__PURE__ */jsxRuntime.jsx(sanity.MemberItemError,{member},member.key);})}):null,!addButtonsAreVisible&&!fieldHasMembers?/* @__PURE__ */jsxRuntime.jsx(ui.Card,{border:true,tone:"transparent",padding:3,radius:2,children:/* @__PURE__ */jsxRuntime.jsx(ui.Text,{size:1,children:"This internationalized field currently has no translations."})}):null,addButtonsAreVisible?/* @__PURE__ */jsxRuntime.jsxs(ui.Stack,{space:2,children:[/* @__PURE__ */jsxRuntime.jsx(AddButtons,{languages:filteredLanguages,value,readOnly,onClick:handleAddLanguage}),buttonAddAll?/* @__PURE__ */jsxRuntime.jsx(ui.Button,{tone:"primary",mode:"ghost",disabled:readOnly||allLanguagesArePresent,icon:icons.AddIcon,text:createAddAllTitle(value,filteredLanguages),onClick:handleAddLanguage}):null]}):null]});}var array=config=>{const{apiVersion,select,languages,type}=config;const typeName=typeof type==="string"?type:type.name;const arrayName=createFieldName(typeName);const objectName=createFieldName(typeName,true);return sanity.defineField({name:arrayName,title:"Internationalized array",type:"array",components:{input:InternationalizedArray},// These options are required for validation rules – not the custom input component
|
|
@@ -9491,9 +9493,9 @@ fields:[typeof type==="string"?// Define a simple field if all we have is the na
|
|
|
9491
9493
|
sanity.defineField({name:"value",type,components:{// TODO: Address this typing issue with the inner object
|
|
9492
9494
|
// @ts-expect-error
|
|
9493
9495
|
field:InternationalizedField}}):// Pass in the configured options, but overwrite the name
|
|
9494
|
-
{...type,name:"value",components:{field:InternationalizedField}}],preview:{select:{title:"value",subtitle:"_key"}}});};function flattenSchemaType(schemaType){if(!sanity.isDocumentSchemaType(schemaType)){console.error("Schema type is not a document");return[];}return extractInnerFields(schemaType.fields,[],3);}function extractInnerFields(fields,path,maxDepth){if(path.length>=maxDepth){return[];}return fields.reduce((acc,field)=>{const thisFieldWithPath={path:[...path,field.name],...field};if(field.type.jsonType==="object"){const innerFields=extractInnerFields(field.type.fields,[...path,field.name],maxDepth);return[...acc,thisFieldWithPath,...innerFields];}else if(field.type.jsonType==="array"&&
|
|
9496
|
+
{...type,name:"value",components:{field:InternationalizedField}}],preview:{select:{title:"value",subtitle:"_key"}}});};function flattenSchemaType(schemaType){if(!sanity.isDocumentSchemaType(schemaType)){console.error("Schema type is not a document");return[];}return extractInnerFields(schemaType.fields,[],3);}function extractInnerFields(fields,path,maxDepth){if(path.length>=maxDepth){return[];}return fields.reduce((acc,field)=>{const thisFieldWithPath={path:[...path,field.name],...field};if(field.type.jsonType==="object"){const innerFields=extractInnerFields(field.type.fields,[...path,field.name],maxDepth);return[...acc,thisFieldWithPath,...innerFields];}else if(field.type.jsonType==="array"&&field.type.of.length&&field.type.of.some(item=>"fields"in item)){const innerFields=extractInnerFields(// TODO: Fix TS assertion for array fields
|
|
9495
9497
|
// @ts-expect-error
|
|
9496
|
-
field.type.of,[...path,field.name],maxDepth);return[...acc,thisFieldWithPath,...innerFields];}return[...acc,thisFieldWithPath];},[]);}const internationalizedArray=sanity.definePlugin(config=>{const pluginConfig={...CONFIG_DEFAULT,...config};const{apiVersion="2022-11-27",select,languages,fieldTypes,defaultLanguages,buttonLocations}=pluginConfig;return{name:"sanity-plugin-internationalized-array",// Preload languages for use throughout the Studio
|
|
9498
|
+
field.type.of[0].fields,[...path,field.name],maxDepth);return[...acc,thisFieldWithPath,...innerFields];}return[...acc,thisFieldWithPath];},[]);}const internationalizedArray=sanity.definePlugin(config=>{const pluginConfig={...CONFIG_DEFAULT,...config};const{apiVersion="2022-11-27",select,languages,fieldTypes,defaultLanguages,buttonLocations}=pluginConfig;return{name:"sanity-plugin-internationalized-array",// Preload languages for use throughout the Studio
|
|
9497
9499
|
studio:Array.isArray(languages)?void 0:{components:{layout:props=>/* @__PURE__ */jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[/* @__PURE__ */jsxRuntime.jsx(Preload,{apiVersion,languages}),props.renderDefault(props)]})}},// Optional: render "add language" buttons as field actions
|
|
9498
9500
|
document:{unstable_fieldActions:buttonLocations.includes("unstable__fieldAction")?prev=>[...prev,internationalizedArrayFieldAction]:void 0},// Wrap document editor with a language provider
|
|
9499
9501
|
form:{components:{input:props=>{const isRootInput=props.id==="root"&&sanity.isObjectInputProps(props);if(!isRootInput){return props.renderDefault(props);}const flatFieldTypeNames=flattenSchemaType(props.schemaType).map(field=>field.type.name);const hasInternationalizedArray=flatFieldTypeNames.some(name=>name.startsWith("internationalizedArray"));if(!hasInternationalizedArray){return props.renderDefault(props);}return InternationalizedArrayProvider({...props,internationalizedArray:pluginConfig});}}},// Register custom schema types for the outer array and the inner object
|