@liiift-studio/sanity-font-manager 2.3.10 → 2.3.12
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/dist/index.js +149 -6
- package/dist/index.mjs +147 -6
- package/package.json +2 -8
- package/src/components/NestedObjectArraySelector.jsx +146 -0
- package/src/hooks/useNestedObjects.js +92 -0
- package/src/index.js +2 -0
- package/src/schema/stylesField.js +0 -6
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ __export(index_exports, {
|
|
|
37
37
|
HtmlDescription: () => HtmlDescription,
|
|
38
38
|
KeyValueInput: () => KeyValueInput,
|
|
39
39
|
KeyValueReferenceInput: () => KeyValueReferenceInput,
|
|
40
|
+
NestedObjectArraySelector: () => NestedObjectArraySelector,
|
|
40
41
|
PriceInput: () => PriceInput_default,
|
|
41
42
|
PrimaryCollectionGeneratorTypeface: () => PrimaryCollectionGeneratorTypeface,
|
|
42
43
|
RegenerateSubfamiliesComponent: () => RegenerateSubfamiliesComponent,
|
|
@@ -82,6 +83,7 @@ __export(index_exports, {
|
|
|
82
83
|
updateFontPrices: () => updateFontPrices,
|
|
83
84
|
updateTypefaceDocument: () => updateTypefaceDocument,
|
|
84
85
|
uploadFontFiles: () => uploadFontFiles,
|
|
86
|
+
useNestedObjects: () => useNestedObjects,
|
|
85
87
|
useSanityClient: () => useSanityClient
|
|
86
88
|
});
|
|
87
89
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -4127,6 +4129,151 @@ var StyleCountInput = (props) => {
|
|
|
4127
4129
|
return /* @__PURE__ */ import_react18.default.createElement(import_ui16.Text, { size: 1 }, count);
|
|
4128
4130
|
};
|
|
4129
4131
|
|
|
4132
|
+
// src/components/NestedObjectArraySelector.jsx
|
|
4133
|
+
var import_react20 = __toESM(require("react"));
|
|
4134
|
+
var import_ui17 = require("@sanity/ui");
|
|
4135
|
+
|
|
4136
|
+
// src/hooks/useNestedObjects.js
|
|
4137
|
+
var import_react19 = require("react");
|
|
4138
|
+
var import_sanity15 = require("sanity");
|
|
4139
|
+
function useNestedObjects({
|
|
4140
|
+
sourceType,
|
|
4141
|
+
nestedField,
|
|
4142
|
+
titleField,
|
|
4143
|
+
valueField,
|
|
4144
|
+
filter = "",
|
|
4145
|
+
sortBy = ""
|
|
4146
|
+
}) {
|
|
4147
|
+
const client = (0, import_sanity15.useClient)({ apiVersion: "2023-01-01" });
|
|
4148
|
+
const [objects, setObjects] = (0, import_react19.useState)([]);
|
|
4149
|
+
const [loading, setLoading] = (0, import_react19.useState)(true);
|
|
4150
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
4151
|
+
(0, import_react19.useEffect)(() => {
|
|
4152
|
+
if (!sourceType || !nestedField || !titleField || !valueField) {
|
|
4153
|
+
setError(new Error("Missing required configuration"));
|
|
4154
|
+
setLoading(false);
|
|
4155
|
+
return;
|
|
4156
|
+
}
|
|
4157
|
+
const fetchData = async () => {
|
|
4158
|
+
try {
|
|
4159
|
+
setLoading(true);
|
|
4160
|
+
setError(null);
|
|
4161
|
+
const filterClause = filter ? ` && ${filter}` : "";
|
|
4162
|
+
const query = `
|
|
4163
|
+
*[_type == "${sourceType}"${filterClause}] {
|
|
4164
|
+
"${nestedField}": ${nestedField}[] {
|
|
4165
|
+
"title": ${titleField},
|
|
4166
|
+
"value": ${valueField}
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
`;
|
|
4170
|
+
const result = await client.fetch(query);
|
|
4171
|
+
if (!result || result.length === 0) {
|
|
4172
|
+
setObjects([]);
|
|
4173
|
+
setLoading(false);
|
|
4174
|
+
return;
|
|
4175
|
+
}
|
|
4176
|
+
const flattened = result.flatMap((doc) => doc[nestedField] || []);
|
|
4177
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
4178
|
+
flattened.forEach((item) => {
|
|
4179
|
+
if (item.value && item.title) uniqueMap.set(item.value, item);
|
|
4180
|
+
});
|
|
4181
|
+
let unique = Array.from(uniqueMap.values());
|
|
4182
|
+
if (sortBy) {
|
|
4183
|
+
const [sortField, sortOrder = "asc"] = sortBy.split(" ");
|
|
4184
|
+
unique = unique.sort((a, b) => {
|
|
4185
|
+
const aVal = a[sortField] || a.title;
|
|
4186
|
+
const bVal = b[sortField] || b.title;
|
|
4187
|
+
const comparison = aVal.localeCompare(bVal);
|
|
4188
|
+
return sortOrder === "desc" ? -comparison : comparison;
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
4191
|
+
setObjects(unique);
|
|
4192
|
+
} catch (err) {
|
|
4193
|
+
console.error("useNestedObjects fetch error:", err);
|
|
4194
|
+
setError(err);
|
|
4195
|
+
} finally {
|
|
4196
|
+
setLoading(false);
|
|
4197
|
+
}
|
|
4198
|
+
};
|
|
4199
|
+
fetchData();
|
|
4200
|
+
}, [sourceType, nestedField, titleField, valueField, filter, sortBy, client]);
|
|
4201
|
+
return { objects, loading, error };
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4204
|
+
// src/components/NestedObjectArraySelector.jsx
|
|
4205
|
+
var import_sanity16 = require("sanity");
|
|
4206
|
+
var NestedObjectArraySelector = import_react20.default.forwardRef((props, ref) => {
|
|
4207
|
+
const { value = [], onChange, schemaType } = props;
|
|
4208
|
+
const options = (schemaType == null ? void 0 : schemaType.options) || {};
|
|
4209
|
+
const {
|
|
4210
|
+
sourceType,
|
|
4211
|
+
nestedField,
|
|
4212
|
+
titleField,
|
|
4213
|
+
valueField,
|
|
4214
|
+
filter = "",
|
|
4215
|
+
sortBy = "title asc",
|
|
4216
|
+
emptyMessage = "No options found",
|
|
4217
|
+
searchPlaceholder = "Search..."
|
|
4218
|
+
} = options;
|
|
4219
|
+
const [searchTerm, setSearchTerm] = (0, import_react20.useState)("");
|
|
4220
|
+
const { objects, loading, error } = useNestedObjects({ sourceType, nestedField, titleField, valueField, filter, sortBy });
|
|
4221
|
+
const filteredObjects = (0, import_react20.useMemo)(() => {
|
|
4222
|
+
if (!searchTerm) return objects;
|
|
4223
|
+
const lower = searchTerm.toLowerCase();
|
|
4224
|
+
return objects.filter((obj) => {
|
|
4225
|
+
var _a;
|
|
4226
|
+
return (_a = obj.title) == null ? void 0 : _a.toLowerCase().includes(lower);
|
|
4227
|
+
});
|
|
4228
|
+
}, [objects, searchTerm]);
|
|
4229
|
+
const handleToggle = (itemValue) => {
|
|
4230
|
+
const currentValue = value || [];
|
|
4231
|
+
const isSelected = currentValue.includes(itemValue);
|
|
4232
|
+
if (isSelected) {
|
|
4233
|
+
const newValue = currentValue.filter((v) => v !== itemValue);
|
|
4234
|
+
onChange(newValue.length > 0 ? (0, import_sanity16.set)(newValue) : (0, import_sanity16.unset)());
|
|
4235
|
+
} else {
|
|
4236
|
+
onChange((0, import_sanity16.set)([...currentValue, itemValue]));
|
|
4237
|
+
}
|
|
4238
|
+
};
|
|
4239
|
+
if (!sourceType || !nestedField || !titleField || !valueField) {
|
|
4240
|
+
return /* @__PURE__ */ import_react20.default.createElement(import_ui17.Card, { padding: 3, tone: "critical", border: true }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Text, { size: 1 }, "Configuration error: Missing required options (sourceType, nestedField, titleField, or valueField)"));
|
|
4241
|
+
}
|
|
4242
|
+
if (loading) {
|
|
4243
|
+
return /* @__PURE__ */ import_react20.default.createElement(import_ui17.Card, { padding: 3, border: true }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Flex, { align: "center", justify: "center", padding: 4 }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Spinner, null), /* @__PURE__ */ import_react20.default.createElement(import_ui17.Box, { marginLeft: 3 }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Text, { size: 1 }, "Loading options..."))));
|
|
4244
|
+
}
|
|
4245
|
+
if (error) {
|
|
4246
|
+
return /* @__PURE__ */ import_react20.default.createElement(import_ui17.Card, { padding: 3, tone: "critical", border: true }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Text, { size: 1 }, "Error loading options: ", error.message));
|
|
4247
|
+
}
|
|
4248
|
+
if (objects.length === 0) {
|
|
4249
|
+
return /* @__PURE__ */ import_react20.default.createElement(import_ui17.Card, { padding: 3, tone: "transparent", border: true }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Text, { size: 1, muted: true }, emptyMessage));
|
|
4250
|
+
}
|
|
4251
|
+
return /* @__PURE__ */ import_react20.default.createElement(import_ui17.Card, { padding: 0, border: true, ref }, objects.length > 5 && /* @__PURE__ */ import_react20.default.createElement(import_ui17.Box, { padding: 3, style: { borderBottom: "1px solid var(--card-border-color)" } }, /* @__PURE__ */ import_react20.default.createElement(
|
|
4252
|
+
"input",
|
|
4253
|
+
{
|
|
4254
|
+
type: "text",
|
|
4255
|
+
placeholder: searchPlaceholder,
|
|
4256
|
+
value: searchTerm,
|
|
4257
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
4258
|
+
style: { width: "100%", padding: "8px 12px", border: "1px solid var(--card-border-color)", borderRadius: "4px", fontSize: "13px", fontFamily: "inherit" }
|
|
4259
|
+
}
|
|
4260
|
+
)), /* @__PURE__ */ import_react20.default.createElement(import_ui17.Stack, { space: 0 }, filteredObjects.length === 0 ? /* @__PURE__ */ import_react20.default.createElement(import_ui17.Box, { padding: 3 }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Text, { size: 1, muted: true }, 'No results found for "', searchTerm, '"')) : filteredObjects.map((obj, index) => {
|
|
4261
|
+
const isSelected = value == null ? void 0 : value.includes(obj.value);
|
|
4262
|
+
const isLast = index === filteredObjects.length - 1;
|
|
4263
|
+
return /* @__PURE__ */ import_react20.default.createElement(
|
|
4264
|
+
import_ui17.Box,
|
|
4265
|
+
{
|
|
4266
|
+
key: obj.value,
|
|
4267
|
+
padding: 3,
|
|
4268
|
+
style: { borderBottom: isLast ? "none" : "1px solid var(--card-border-color)", cursor: "pointer", backgroundColor: isSelected ? "var(--card-muted-fg-color)" : "transparent", transition: "background-color 0.2s" },
|
|
4269
|
+
onClick: () => handleToggle(obj.value)
|
|
4270
|
+
},
|
|
4271
|
+
/* @__PURE__ */ import_react20.default.createElement(import_ui17.Flex, { align: "center", gap: 3 }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Checkbox, { checked: isSelected, readOnly: true, style: { pointerEvents: "none" } }), /* @__PURE__ */ import_react20.default.createElement(import_ui17.Text, { size: 1, weight: isSelected ? "semibold" : "regular" }, obj.title))
|
|
4272
|
+
);
|
|
4273
|
+
})), (value == null ? void 0 : value.length) > 0 && /* @__PURE__ */ import_react20.default.createElement(import_ui17.Box, { padding: 2, paddingX: 3, style: { borderTop: "1px solid var(--card-border-color)", backgroundColor: "var(--card-muted-fg-color)" } }, /* @__PURE__ */ import_react20.default.createElement(import_ui17.Text, { size: 1, muted: true }, value.length, " selected")));
|
|
4274
|
+
});
|
|
4275
|
+
NestedObjectArraySelector.displayName = "NestedObjectArraySelector";
|
|
4276
|
+
|
|
4130
4277
|
// src/utils/getEmptyFontKit.js
|
|
4131
4278
|
var fontkit7 = __toESM(require("fontkit"));
|
|
4132
4279
|
var import_slugify4 = __toESM(require("slugify"));
|
|
@@ -6659,7 +6806,6 @@ var stylisticSetField = {
|
|
|
6659
6806
|
};
|
|
6660
6807
|
|
|
6661
6808
|
// src/schema/stylesField.js
|
|
6662
|
-
var import_sanity_advanced_reference_array = require("sanity-advanced-reference-array");
|
|
6663
6809
|
var field = (condition, def) => condition ? [def] : [];
|
|
6664
6810
|
var fontsFilter = async ({ getClient, document, parent }) => {
|
|
6665
6811
|
const client = getClient({ apiVersion: "2022-11-09" });
|
|
@@ -6734,7 +6880,6 @@ function createStylesField({
|
|
|
6734
6880
|
title: "Fonts",
|
|
6735
6881
|
name: "fonts",
|
|
6736
6882
|
type: "array",
|
|
6737
|
-
components: { input: import_sanity_advanced_reference_array.AdvancedRefArray },
|
|
6738
6883
|
of: [{ type: "reference", weak: true, to: [{ type: "font" }] }],
|
|
6739
6884
|
options: {
|
|
6740
6885
|
sortable: true,
|
|
@@ -6811,7 +6956,6 @@ function createStylesField({
|
|
|
6811
6956
|
title: "Fonts",
|
|
6812
6957
|
name: "fonts",
|
|
6813
6958
|
type: "array",
|
|
6814
|
-
components: { input: import_sanity_advanced_reference_array.AdvancedRefArray },
|
|
6815
6959
|
of: [{
|
|
6816
6960
|
type: "reference",
|
|
6817
6961
|
weak: true,
|
|
@@ -6824,7 +6968,6 @@ function createStylesField({
|
|
|
6824
6968
|
title: "Variable Fonts",
|
|
6825
6969
|
name: "variableFont",
|
|
6826
6970
|
type: "array",
|
|
6827
|
-
components: { input: import_sanity_advanced_reference_array.AdvancedRefArray },
|
|
6828
6971
|
of: [{
|
|
6829
6972
|
type: "reference",
|
|
6830
6973
|
weak: true,
|
|
@@ -6855,7 +6998,6 @@ function createStylesField({
|
|
|
6855
6998
|
title: "Collections",
|
|
6856
6999
|
name: "collections",
|
|
6857
7000
|
type: "array",
|
|
6858
|
-
components: { input: import_sanity_advanced_reference_array.AdvancedRefArray },
|
|
6859
7001
|
of: [{ type: "reference", weak: true, to: [{ type: "collection" }] }],
|
|
6860
7002
|
options: { sortable: true },
|
|
6861
7003
|
validation: (Rule) => Rule.unique()
|
|
@@ -6864,7 +7006,6 @@ function createStylesField({
|
|
|
6864
7006
|
title: "Pairs",
|
|
6865
7007
|
name: "pairs",
|
|
6866
7008
|
type: "array",
|
|
6867
|
-
components: { input: import_sanity_advanced_reference_array.AdvancedRefArray },
|
|
6868
7009
|
of: [{ type: "reference", weak: true, to: [{ type: "pair" }] }],
|
|
6869
7010
|
options: { sortable: true },
|
|
6870
7011
|
validation: (Rule) => Rule.unique(),
|
|
@@ -6890,6 +7031,7 @@ function createStylesField({
|
|
|
6890
7031
|
HtmlDescription,
|
|
6891
7032
|
KeyValueInput,
|
|
6892
7033
|
KeyValueReferenceInput,
|
|
7034
|
+
NestedObjectArraySelector,
|
|
6893
7035
|
PriceInput,
|
|
6894
7036
|
PrimaryCollectionGeneratorTypeface,
|
|
6895
7037
|
RegenerateSubfamiliesComponent,
|
|
@@ -6935,5 +7077,6 @@ function createStylesField({
|
|
|
6935
7077
|
updateFontPrices,
|
|
6936
7078
|
updateTypefaceDocument,
|
|
6937
7079
|
uploadFontFiles,
|
|
7080
|
+
useNestedObjects,
|
|
6938
7081
|
useSanityClient
|
|
6939
7082
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -4039,6 +4039,151 @@ var StyleCountInput = (props) => {
|
|
|
4039
4039
|
return /* @__PURE__ */ React17.createElement(Text15, { size: 1 }, count);
|
|
4040
4040
|
};
|
|
4041
4041
|
|
|
4042
|
+
// src/components/NestedObjectArraySelector.jsx
|
|
4043
|
+
import React18, { useMemo as useMemo5, useState as useState14 } from "react";
|
|
4044
|
+
import { Stack as Stack13, Card as Card6, Text as Text16, Checkbox, Box as Box6, Spinner as Spinner4, Flex as Flex11 } from "@sanity/ui";
|
|
4045
|
+
|
|
4046
|
+
// src/hooks/useNestedObjects.js
|
|
4047
|
+
import { useState as useState13, useEffect as useEffect7 } from "react";
|
|
4048
|
+
import { useClient as useClient2 } from "sanity";
|
|
4049
|
+
function useNestedObjects({
|
|
4050
|
+
sourceType,
|
|
4051
|
+
nestedField,
|
|
4052
|
+
titleField,
|
|
4053
|
+
valueField,
|
|
4054
|
+
filter = "",
|
|
4055
|
+
sortBy = ""
|
|
4056
|
+
}) {
|
|
4057
|
+
const client = useClient2({ apiVersion: "2023-01-01" });
|
|
4058
|
+
const [objects, setObjects] = useState13([]);
|
|
4059
|
+
const [loading, setLoading] = useState13(true);
|
|
4060
|
+
const [error, setError] = useState13(null);
|
|
4061
|
+
useEffect7(() => {
|
|
4062
|
+
if (!sourceType || !nestedField || !titleField || !valueField) {
|
|
4063
|
+
setError(new Error("Missing required configuration"));
|
|
4064
|
+
setLoading(false);
|
|
4065
|
+
return;
|
|
4066
|
+
}
|
|
4067
|
+
const fetchData = async () => {
|
|
4068
|
+
try {
|
|
4069
|
+
setLoading(true);
|
|
4070
|
+
setError(null);
|
|
4071
|
+
const filterClause = filter ? ` && ${filter}` : "";
|
|
4072
|
+
const query = `
|
|
4073
|
+
*[_type == "${sourceType}"${filterClause}] {
|
|
4074
|
+
"${nestedField}": ${nestedField}[] {
|
|
4075
|
+
"title": ${titleField},
|
|
4076
|
+
"value": ${valueField}
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4079
|
+
`;
|
|
4080
|
+
const result = await client.fetch(query);
|
|
4081
|
+
if (!result || result.length === 0) {
|
|
4082
|
+
setObjects([]);
|
|
4083
|
+
setLoading(false);
|
|
4084
|
+
return;
|
|
4085
|
+
}
|
|
4086
|
+
const flattened = result.flatMap((doc) => doc[nestedField] || []);
|
|
4087
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
4088
|
+
flattened.forEach((item) => {
|
|
4089
|
+
if (item.value && item.title) uniqueMap.set(item.value, item);
|
|
4090
|
+
});
|
|
4091
|
+
let unique = Array.from(uniqueMap.values());
|
|
4092
|
+
if (sortBy) {
|
|
4093
|
+
const [sortField, sortOrder = "asc"] = sortBy.split(" ");
|
|
4094
|
+
unique = unique.sort((a, b) => {
|
|
4095
|
+
const aVal = a[sortField] || a.title;
|
|
4096
|
+
const bVal = b[sortField] || b.title;
|
|
4097
|
+
const comparison = aVal.localeCompare(bVal);
|
|
4098
|
+
return sortOrder === "desc" ? -comparison : comparison;
|
|
4099
|
+
});
|
|
4100
|
+
}
|
|
4101
|
+
setObjects(unique);
|
|
4102
|
+
} catch (err) {
|
|
4103
|
+
console.error("useNestedObjects fetch error:", err);
|
|
4104
|
+
setError(err);
|
|
4105
|
+
} finally {
|
|
4106
|
+
setLoading(false);
|
|
4107
|
+
}
|
|
4108
|
+
};
|
|
4109
|
+
fetchData();
|
|
4110
|
+
}, [sourceType, nestedField, titleField, valueField, filter, sortBy, client]);
|
|
4111
|
+
return { objects, loading, error };
|
|
4112
|
+
}
|
|
4113
|
+
|
|
4114
|
+
// src/components/NestedObjectArraySelector.jsx
|
|
4115
|
+
import { set as set8, unset as unset3 } from "sanity";
|
|
4116
|
+
var NestedObjectArraySelector = React18.forwardRef((props, ref) => {
|
|
4117
|
+
const { value = [], onChange, schemaType } = props;
|
|
4118
|
+
const options = (schemaType == null ? void 0 : schemaType.options) || {};
|
|
4119
|
+
const {
|
|
4120
|
+
sourceType,
|
|
4121
|
+
nestedField,
|
|
4122
|
+
titleField,
|
|
4123
|
+
valueField,
|
|
4124
|
+
filter = "",
|
|
4125
|
+
sortBy = "title asc",
|
|
4126
|
+
emptyMessage = "No options found",
|
|
4127
|
+
searchPlaceholder = "Search..."
|
|
4128
|
+
} = options;
|
|
4129
|
+
const [searchTerm, setSearchTerm] = useState14("");
|
|
4130
|
+
const { objects, loading, error } = useNestedObjects({ sourceType, nestedField, titleField, valueField, filter, sortBy });
|
|
4131
|
+
const filteredObjects = useMemo5(() => {
|
|
4132
|
+
if (!searchTerm) return objects;
|
|
4133
|
+
const lower = searchTerm.toLowerCase();
|
|
4134
|
+
return objects.filter((obj) => {
|
|
4135
|
+
var _a;
|
|
4136
|
+
return (_a = obj.title) == null ? void 0 : _a.toLowerCase().includes(lower);
|
|
4137
|
+
});
|
|
4138
|
+
}, [objects, searchTerm]);
|
|
4139
|
+
const handleToggle = (itemValue) => {
|
|
4140
|
+
const currentValue = value || [];
|
|
4141
|
+
const isSelected = currentValue.includes(itemValue);
|
|
4142
|
+
if (isSelected) {
|
|
4143
|
+
const newValue = currentValue.filter((v) => v !== itemValue);
|
|
4144
|
+
onChange(newValue.length > 0 ? set8(newValue) : unset3());
|
|
4145
|
+
} else {
|
|
4146
|
+
onChange(set8([...currentValue, itemValue]));
|
|
4147
|
+
}
|
|
4148
|
+
};
|
|
4149
|
+
if (!sourceType || !nestedField || !titleField || !valueField) {
|
|
4150
|
+
return /* @__PURE__ */ React18.createElement(Card6, { padding: 3, tone: "critical", border: true }, /* @__PURE__ */ React18.createElement(Text16, { size: 1 }, "Configuration error: Missing required options (sourceType, nestedField, titleField, or valueField)"));
|
|
4151
|
+
}
|
|
4152
|
+
if (loading) {
|
|
4153
|
+
return /* @__PURE__ */ React18.createElement(Card6, { padding: 3, border: true }, /* @__PURE__ */ React18.createElement(Flex11, { align: "center", justify: "center", padding: 4 }, /* @__PURE__ */ React18.createElement(Spinner4, null), /* @__PURE__ */ React18.createElement(Box6, { marginLeft: 3 }, /* @__PURE__ */ React18.createElement(Text16, { size: 1 }, "Loading options..."))));
|
|
4154
|
+
}
|
|
4155
|
+
if (error) {
|
|
4156
|
+
return /* @__PURE__ */ React18.createElement(Card6, { padding: 3, tone: "critical", border: true }, /* @__PURE__ */ React18.createElement(Text16, { size: 1 }, "Error loading options: ", error.message));
|
|
4157
|
+
}
|
|
4158
|
+
if (objects.length === 0) {
|
|
4159
|
+
return /* @__PURE__ */ React18.createElement(Card6, { padding: 3, tone: "transparent", border: true }, /* @__PURE__ */ React18.createElement(Text16, { size: 1, muted: true }, emptyMessage));
|
|
4160
|
+
}
|
|
4161
|
+
return /* @__PURE__ */ React18.createElement(Card6, { padding: 0, border: true, ref }, objects.length > 5 && /* @__PURE__ */ React18.createElement(Box6, { padding: 3, style: { borderBottom: "1px solid var(--card-border-color)" } }, /* @__PURE__ */ React18.createElement(
|
|
4162
|
+
"input",
|
|
4163
|
+
{
|
|
4164
|
+
type: "text",
|
|
4165
|
+
placeholder: searchPlaceholder,
|
|
4166
|
+
value: searchTerm,
|
|
4167
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
4168
|
+
style: { width: "100%", padding: "8px 12px", border: "1px solid var(--card-border-color)", borderRadius: "4px", fontSize: "13px", fontFamily: "inherit" }
|
|
4169
|
+
}
|
|
4170
|
+
)), /* @__PURE__ */ React18.createElement(Stack13, { space: 0 }, filteredObjects.length === 0 ? /* @__PURE__ */ React18.createElement(Box6, { padding: 3 }, /* @__PURE__ */ React18.createElement(Text16, { size: 1, muted: true }, 'No results found for "', searchTerm, '"')) : filteredObjects.map((obj, index) => {
|
|
4171
|
+
const isSelected = value == null ? void 0 : value.includes(obj.value);
|
|
4172
|
+
const isLast = index === filteredObjects.length - 1;
|
|
4173
|
+
return /* @__PURE__ */ React18.createElement(
|
|
4174
|
+
Box6,
|
|
4175
|
+
{
|
|
4176
|
+
key: obj.value,
|
|
4177
|
+
padding: 3,
|
|
4178
|
+
style: { borderBottom: isLast ? "none" : "1px solid var(--card-border-color)", cursor: "pointer", backgroundColor: isSelected ? "var(--card-muted-fg-color)" : "transparent", transition: "background-color 0.2s" },
|
|
4179
|
+
onClick: () => handleToggle(obj.value)
|
|
4180
|
+
},
|
|
4181
|
+
/* @__PURE__ */ React18.createElement(Flex11, { align: "center", gap: 3 }, /* @__PURE__ */ React18.createElement(Checkbox, { checked: isSelected, readOnly: true, style: { pointerEvents: "none" } }), /* @__PURE__ */ React18.createElement(Text16, { size: 1, weight: isSelected ? "semibold" : "regular" }, obj.title))
|
|
4182
|
+
);
|
|
4183
|
+
})), (value == null ? void 0 : value.length) > 0 && /* @__PURE__ */ React18.createElement(Box6, { padding: 2, paddingX: 3, style: { borderTop: "1px solid var(--card-border-color)", backgroundColor: "var(--card-muted-fg-color)" } }, /* @__PURE__ */ React18.createElement(Text16, { size: 1, muted: true }, value.length, " selected")));
|
|
4184
|
+
});
|
|
4185
|
+
NestedObjectArraySelector.displayName = "NestedObjectArraySelector";
|
|
4186
|
+
|
|
4042
4187
|
// src/utils/getEmptyFontKit.js
|
|
4043
4188
|
import * as fontkit7 from "fontkit";
|
|
4044
4189
|
import slugify4 from "slugify";
|
|
@@ -6571,7 +6716,6 @@ var stylisticSetField = {
|
|
|
6571
6716
|
};
|
|
6572
6717
|
|
|
6573
6718
|
// src/schema/stylesField.js
|
|
6574
|
-
import { AdvancedRefArray } from "sanity-advanced-reference-array";
|
|
6575
6719
|
var field = (condition, def) => condition ? [def] : [];
|
|
6576
6720
|
var fontsFilter = async ({ getClient, document, parent }) => {
|
|
6577
6721
|
const client = getClient({ apiVersion: "2022-11-09" });
|
|
@@ -6646,7 +6790,6 @@ function createStylesField({
|
|
|
6646
6790
|
title: "Fonts",
|
|
6647
6791
|
name: "fonts",
|
|
6648
6792
|
type: "array",
|
|
6649
|
-
components: { input: AdvancedRefArray },
|
|
6650
6793
|
of: [{ type: "reference", weak: true, to: [{ type: "font" }] }],
|
|
6651
6794
|
options: {
|
|
6652
6795
|
sortable: true,
|
|
@@ -6723,7 +6866,6 @@ function createStylesField({
|
|
|
6723
6866
|
title: "Fonts",
|
|
6724
6867
|
name: "fonts",
|
|
6725
6868
|
type: "array",
|
|
6726
|
-
components: { input: AdvancedRefArray },
|
|
6727
6869
|
of: [{
|
|
6728
6870
|
type: "reference",
|
|
6729
6871
|
weak: true,
|
|
@@ -6736,7 +6878,6 @@ function createStylesField({
|
|
|
6736
6878
|
title: "Variable Fonts",
|
|
6737
6879
|
name: "variableFont",
|
|
6738
6880
|
type: "array",
|
|
6739
|
-
components: { input: AdvancedRefArray },
|
|
6740
6881
|
of: [{
|
|
6741
6882
|
type: "reference",
|
|
6742
6883
|
weak: true,
|
|
@@ -6767,7 +6908,6 @@ function createStylesField({
|
|
|
6767
6908
|
title: "Collections",
|
|
6768
6909
|
name: "collections",
|
|
6769
6910
|
type: "array",
|
|
6770
|
-
components: { input: AdvancedRefArray },
|
|
6771
6911
|
of: [{ type: "reference", weak: true, to: [{ type: "collection" }] }],
|
|
6772
6912
|
options: { sortable: true },
|
|
6773
6913
|
validation: (Rule) => Rule.unique()
|
|
@@ -6776,7 +6916,6 @@ function createStylesField({
|
|
|
6776
6916
|
title: "Pairs",
|
|
6777
6917
|
name: "pairs",
|
|
6778
6918
|
type: "array",
|
|
6779
|
-
components: { input: AdvancedRefArray },
|
|
6780
6919
|
of: [{ type: "reference", weak: true, to: [{ type: "pair" }] }],
|
|
6781
6920
|
options: { sortable: true },
|
|
6782
6921
|
validation: (Rule) => Rule.unique(),
|
|
@@ -6801,6 +6940,7 @@ export {
|
|
|
6801
6940
|
HtmlDescription,
|
|
6802
6941
|
KeyValueInput,
|
|
6803
6942
|
KeyValueReferenceInput,
|
|
6943
|
+
NestedObjectArraySelector,
|
|
6804
6944
|
PriceInput_default as PriceInput,
|
|
6805
6945
|
PrimaryCollectionGeneratorTypeface,
|
|
6806
6946
|
RegenerateSubfamiliesComponent,
|
|
@@ -6846,5 +6986,6 @@ export {
|
|
|
6846
6986
|
updateFontPrices,
|
|
6847
6987
|
updateTypefaceDocument,
|
|
6848
6988
|
uploadFontFiles,
|
|
6989
|
+
useNestedObjects,
|
|
6849
6990
|
useSanityClient
|
|
6850
6991
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liiift-studio/sanity-font-manager",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.12",
|
|
4
4
|
"description": "Sanity Studio plugin — full font management suite with batch upload, format conversion, metadata extraction, CSS generation, collection/pair generation, and script variant support. Supports Sanity v3, v4, and v5.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Liiift Studio",
|
|
@@ -59,13 +59,7 @@
|
|
|
59
59
|
"@sanity/icons": ">=3",
|
|
60
60
|
"@sanity/ui": ">=3",
|
|
61
61
|
"react": ">=18",
|
|
62
|
-
"sanity": ">=3"
|
|
63
|
-
"sanity-advanced-reference-array": ">=1"
|
|
64
|
-
},
|
|
65
|
-
"peerDependenciesMeta": {
|
|
66
|
-
"sanity-advanced-reference-array": {
|
|
67
|
-
"optional": true
|
|
68
|
-
}
|
|
62
|
+
"sanity": ">=3"
|
|
69
63
|
},
|
|
70
64
|
"devDependencies": {
|
|
71
65
|
"@sanity/icons": "^3",
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Generic checkbox-list selector for nested objects from Sanity documents — configured via schema options
|
|
2
|
+
|
|
3
|
+
import React, { useMemo, useState } from 'react';
|
|
4
|
+
import { Stack, Card, Text, Checkbox, Box, Spinner, Flex } from '@sanity/ui';
|
|
5
|
+
import { useNestedObjects } from '../hooks/useNestedObjects';
|
|
6
|
+
import { set, unset } from 'sanity';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Sanity input component that renders a searchable checkbox list of items fetched
|
|
10
|
+
* from nested arrays inside Sanity documents.
|
|
11
|
+
*
|
|
12
|
+
* Configure via schema options:
|
|
13
|
+
* ```js
|
|
14
|
+
* components: { input: NestedObjectArraySelector },
|
|
15
|
+
* options: {
|
|
16
|
+
* sourceType: 'licenseGroup', // document type to query
|
|
17
|
+
* nestedField: 'sections', // array field to extract
|
|
18
|
+
* titleField: 'title', // GROQ expression for display text
|
|
19
|
+
* valueField: 'slug.current', // GROQ expression for stored value
|
|
20
|
+
* filter: 'state == "published"', // optional GROQ filter
|
|
21
|
+
* sortBy: 'title asc', // optional sort field + direction
|
|
22
|
+
* emptyMessage: 'No options found', // optional empty state text
|
|
23
|
+
* searchPlaceholder: 'Search...', // optional search input placeholder
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const NestedObjectArraySelector = React.forwardRef((props, ref) => {
|
|
28
|
+
const { value = [], onChange, schemaType } = props;
|
|
29
|
+
|
|
30
|
+
const options = schemaType?.options || {};
|
|
31
|
+
const {
|
|
32
|
+
sourceType,
|
|
33
|
+
nestedField,
|
|
34
|
+
titleField,
|
|
35
|
+
valueField,
|
|
36
|
+
filter = '',
|
|
37
|
+
sortBy = 'title asc',
|
|
38
|
+
emptyMessage = 'No options found',
|
|
39
|
+
searchPlaceholder = 'Search...',
|
|
40
|
+
} = options;
|
|
41
|
+
|
|
42
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
43
|
+
const { objects, loading, error } = useNestedObjects({ sourceType, nestedField, titleField, valueField, filter, sortBy });
|
|
44
|
+
|
|
45
|
+
const filteredObjects = useMemo(() => {
|
|
46
|
+
if (!searchTerm) return objects;
|
|
47
|
+
const lower = searchTerm.toLowerCase();
|
|
48
|
+
return objects.filter(obj => obj.title?.toLowerCase().includes(lower));
|
|
49
|
+
}, [objects, searchTerm]);
|
|
50
|
+
|
|
51
|
+
const handleToggle = (itemValue) => {
|
|
52
|
+
const currentValue = value || [];
|
|
53
|
+
const isSelected = currentValue.includes(itemValue);
|
|
54
|
+
if (isSelected) {
|
|
55
|
+
const newValue = currentValue.filter(v => v !== itemValue);
|
|
56
|
+
onChange(newValue.length > 0 ? set(newValue) : unset());
|
|
57
|
+
} else {
|
|
58
|
+
onChange(set([...currentValue, itemValue]));
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (!sourceType || !nestedField || !titleField || !valueField) {
|
|
63
|
+
return (
|
|
64
|
+
<Card padding={3} tone="critical" border>
|
|
65
|
+
<Text size={1}>Configuration error: Missing required options (sourceType, nestedField, titleField, or valueField)</Text>
|
|
66
|
+
</Card>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (loading) {
|
|
71
|
+
return (
|
|
72
|
+
<Card padding={3} border>
|
|
73
|
+
<Flex align="center" justify="center" padding={4}>
|
|
74
|
+
<Spinner />
|
|
75
|
+
<Box marginLeft={3}><Text size={1}>Loading options...</Text></Box>
|
|
76
|
+
</Flex>
|
|
77
|
+
</Card>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (error) {
|
|
82
|
+
return (
|
|
83
|
+
<Card padding={3} tone="critical" border>
|
|
84
|
+
<Text size={1}>Error loading options: {error.message}</Text>
|
|
85
|
+
</Card>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (objects.length === 0) {
|
|
90
|
+
return (
|
|
91
|
+
<Card padding={3} tone="transparent" border>
|
|
92
|
+
<Text size={1} muted>{emptyMessage}</Text>
|
|
93
|
+
</Card>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<Card padding={0} border ref={ref}>
|
|
99
|
+
{objects.length > 5 && (
|
|
100
|
+
<Box padding={3} style={{ borderBottom: '1px solid var(--card-border-color)' }}>
|
|
101
|
+
<input
|
|
102
|
+
type="text"
|
|
103
|
+
placeholder={searchPlaceholder}
|
|
104
|
+
value={searchTerm}
|
|
105
|
+
onChange={(e) => setSearchTerm(e.target.value)}
|
|
106
|
+
style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--card-border-color)', borderRadius: '4px', fontSize: '13px', fontFamily: 'inherit' }}
|
|
107
|
+
/>
|
|
108
|
+
</Box>
|
|
109
|
+
)}
|
|
110
|
+
|
|
111
|
+
<Stack space={0}>
|
|
112
|
+
{filteredObjects.length === 0 ? (
|
|
113
|
+
<Box padding={3}>
|
|
114
|
+
<Text size={1} muted>No results found for "{searchTerm}"</Text>
|
|
115
|
+
</Box>
|
|
116
|
+
) : (
|
|
117
|
+
filteredObjects.map((obj, index) => {
|
|
118
|
+
const isSelected = value?.includes(obj.value);
|
|
119
|
+
const isLast = index === filteredObjects.length - 1;
|
|
120
|
+
return (
|
|
121
|
+
<Box
|
|
122
|
+
key={obj.value}
|
|
123
|
+
padding={3}
|
|
124
|
+
style={{ borderBottom: isLast ? 'none' : '1px solid var(--card-border-color)', cursor: 'pointer', backgroundColor: isSelected ? 'var(--card-muted-fg-color)' : 'transparent', transition: 'background-color 0.2s' }}
|
|
125
|
+
onClick={() => handleToggle(obj.value)}
|
|
126
|
+
>
|
|
127
|
+
<Flex align="center" gap={3}>
|
|
128
|
+
<Checkbox checked={isSelected} readOnly style={{ pointerEvents: 'none' }} />
|
|
129
|
+
<Text size={1} weight={isSelected ? 'semibold' : 'regular'}>{obj.title}</Text>
|
|
130
|
+
</Flex>
|
|
131
|
+
</Box>
|
|
132
|
+
);
|
|
133
|
+
})
|
|
134
|
+
)}
|
|
135
|
+
</Stack>
|
|
136
|
+
|
|
137
|
+
{value?.length > 0 && (
|
|
138
|
+
<Box padding={2} paddingX={3} style={{ borderTop: '1px solid var(--card-border-color)', backgroundColor: 'var(--card-muted-fg-color)' }}>
|
|
139
|
+
<Text size={1} muted>{value.length} selected</Text>
|
|
140
|
+
</Box>
|
|
141
|
+
)}
|
|
142
|
+
</Card>
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
NestedObjectArraySelector.displayName = 'NestedObjectArraySelector';
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Hook for fetching nested objects from Sanity documents — used by NestedObjectArraySelector
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { useClient } from 'sanity';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Fetches and flattens nested arrays from a Sanity document type into a list of selectable items.
|
|
8
|
+
* @param {Object} config
|
|
9
|
+
* @param {string} config.sourceType - Document type to query (e.g. 'licenseGroup')
|
|
10
|
+
* @param {string} config.nestedField - Array field to extract from (e.g. 'sections')
|
|
11
|
+
* @param {string} config.titleField - GROQ expression for display text (e.g. 'title')
|
|
12
|
+
* @param {string} config.valueField - GROQ expression for stored value (e.g. 'slug.current')
|
|
13
|
+
* @param {string} [config.filter] - Optional GROQ filter clause (e.g. 'state == "published"')
|
|
14
|
+
* @param {string} [config.sortBy] - Optional sort field and direction (e.g. 'title asc')
|
|
15
|
+
* @returns {{ objects: Array, loading: boolean, error: Error|null }}
|
|
16
|
+
*/
|
|
17
|
+
export function useNestedObjects({
|
|
18
|
+
sourceType,
|
|
19
|
+
nestedField,
|
|
20
|
+
titleField,
|
|
21
|
+
valueField,
|
|
22
|
+
filter = '',
|
|
23
|
+
sortBy = '',
|
|
24
|
+
}) {
|
|
25
|
+
const client = useClient({ apiVersion: '2023-01-01' });
|
|
26
|
+
const [objects, setObjects] = useState([]);
|
|
27
|
+
const [loading, setLoading] = useState(true);
|
|
28
|
+
const [error, setError] = useState(null);
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!sourceType || !nestedField || !titleField || !valueField) {
|
|
32
|
+
setError(new Error('Missing required configuration'));
|
|
33
|
+
setLoading(false);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const fetchData = async () => {
|
|
38
|
+
try {
|
|
39
|
+
setLoading(true);
|
|
40
|
+
setError(null);
|
|
41
|
+
|
|
42
|
+
const filterClause = filter ? ` && ${filter}` : '';
|
|
43
|
+
const query = `
|
|
44
|
+
*[_type == "${sourceType}"${filterClause}] {
|
|
45
|
+
"${nestedField}": ${nestedField}[] {
|
|
46
|
+
"title": ${titleField},
|
|
47
|
+
"value": ${valueField}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const result = await client.fetch(query);
|
|
53
|
+
|
|
54
|
+
if (!result || result.length === 0) {
|
|
55
|
+
setObjects([]);
|
|
56
|
+
setLoading(false);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Flatten nested arrays from all documents and deduplicate by value
|
|
61
|
+
const flattened = result.flatMap(doc => doc[nestedField] || []);
|
|
62
|
+
const uniqueMap = new Map();
|
|
63
|
+
flattened.forEach(item => {
|
|
64
|
+
if (item.value && item.title) uniqueMap.set(item.value, item);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
let unique = Array.from(uniqueMap.values());
|
|
68
|
+
|
|
69
|
+
if (sortBy) {
|
|
70
|
+
const [sortField, sortOrder = 'asc'] = sortBy.split(' ');
|
|
71
|
+
unique = unique.sort((a, b) => {
|
|
72
|
+
const aVal = a[sortField] || a.title;
|
|
73
|
+
const bVal = b[sortField] || b.title;
|
|
74
|
+
const comparison = aVal.localeCompare(bVal);
|
|
75
|
+
return sortOrder === 'desc' ? -comparison : comparison;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
setObjects(unique);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
console.error('useNestedObjects fetch error:', err);
|
|
82
|
+
setError(err);
|
|
83
|
+
} finally {
|
|
84
|
+
setLoading(false);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
fetchData();
|
|
89
|
+
}, [sourceType, nestedField, titleField, valueField, filter, sortBy, client]);
|
|
90
|
+
|
|
91
|
+
return { objects, loading, error };
|
|
92
|
+
}
|
package/src/index.js
CHANGED
|
@@ -17,9 +17,11 @@ export { VariableInstanceReferencesInput } from './components/VariableInstanceRe
|
|
|
17
17
|
export { PrimaryCollectionGeneratorTypeface } from './components/PrimaryCollectionGeneratorTypeface.jsx';
|
|
18
18
|
export { SetOTF } from './components/SetOTF.jsx';
|
|
19
19
|
export { StyleCountInput } from './components/StyleCountInput.jsx';
|
|
20
|
+
export { NestedObjectArraySelector } from './components/NestedObjectArraySelector.jsx';
|
|
20
21
|
|
|
21
22
|
// Hooks
|
|
22
23
|
export { useSanityClient } from './hooks/useSanityClient.js';
|
|
24
|
+
export { useNestedObjects } from './hooks/useNestedObjects.js';
|
|
23
25
|
|
|
24
26
|
// Core utilities
|
|
25
27
|
export { default as generateCssFile } from './utils/generateCssFile.js';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// Sanity schema factory function for the Styles object field — call createStylesField(options) to generate the field definition for a typeface document
|
|
2
|
-
import { AdvancedRefArray } from 'sanity-advanced-reference-array';
|
|
3
2
|
import { RegenerateSubfamiliesComponent } from '../components/RegenerateSubfamiliesComponent.jsx';
|
|
4
3
|
|
|
5
4
|
// Conditionally includes a field definition in an array
|
|
@@ -102,7 +101,6 @@ export function createStylesField({
|
|
|
102
101
|
title: 'Fonts',
|
|
103
102
|
name: 'fonts',
|
|
104
103
|
type: 'array',
|
|
105
|
-
components: { input: AdvancedRefArray },
|
|
106
104
|
of: [{ type: 'reference', weak: true, to: [{ type: 'font' }] }],
|
|
107
105
|
options: {
|
|
108
106
|
sortable: true,
|
|
@@ -181,7 +179,6 @@ export function createStylesField({
|
|
|
181
179
|
title: 'Fonts',
|
|
182
180
|
name: 'fonts',
|
|
183
181
|
type: 'array',
|
|
184
|
-
components: { input: AdvancedRefArray },
|
|
185
182
|
of: [{
|
|
186
183
|
type: 'reference',
|
|
187
184
|
weak: true,
|
|
@@ -194,7 +191,6 @@ export function createStylesField({
|
|
|
194
191
|
title: 'Variable Fonts',
|
|
195
192
|
name: 'variableFont',
|
|
196
193
|
type: 'array',
|
|
197
|
-
components: { input: AdvancedRefArray },
|
|
198
194
|
of: [{
|
|
199
195
|
type: 'reference',
|
|
200
196
|
weak: true,
|
|
@@ -222,7 +218,6 @@ export function createStylesField({
|
|
|
222
218
|
title: 'Collections',
|
|
223
219
|
name: 'collections',
|
|
224
220
|
type: 'array',
|
|
225
|
-
components: { input: AdvancedRefArray },
|
|
226
221
|
of: [{ type: 'reference', weak: true, to: [{ type: 'collection' }] }],
|
|
227
222
|
options: { sortable: true },
|
|
228
223
|
validation: Rule => Rule.unique(),
|
|
@@ -231,7 +226,6 @@ export function createStylesField({
|
|
|
231
226
|
title: 'Pairs',
|
|
232
227
|
name: 'pairs',
|
|
233
228
|
type: 'array',
|
|
234
|
-
components: { input: AdvancedRefArray },
|
|
235
229
|
of: [{ type: 'reference', weak: true, to: [{ type: 'pair' }] }],
|
|
236
230
|
options: { sortable: true },
|
|
237
231
|
validation: Rule => Rule.unique(),
|