attrs-in-props 3.14.0 → 3.14.1
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/cjs/index.js +8 -177
- package/dist/cjs/package.json +4 -0
- package/index.js +38 -4
- package/package.json +1 -1
- package/dist/esm/index.js +0 -1159
- package/dist/iife/index.js +0 -1582
package/dist/cjs/index.js
CHANGED
|
@@ -19,20 +19,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var index_exports = {};
|
|
20
20
|
__export(index_exports, {
|
|
21
21
|
ARIA_ROLES: () => ARIA_ROLES,
|
|
22
|
-
ATTR_TRANSFORMS: () => ATTR_TRANSFORMS,
|
|
23
22
|
DOM_EVENTS: () => DOM_EVENTS,
|
|
24
23
|
HTML_ATTRIBUTES: () => HTML_ATTRIBUTES,
|
|
25
|
-
applyAttrTransforms: () => applyAttrTransforms,
|
|
26
24
|
checkAttributeByTagName: () => checkAttributeByTagName,
|
|
27
25
|
checkEventFunctions: () => checkEventFunctions,
|
|
28
26
|
executeAttr: () => executeAttr,
|
|
29
|
-
|
|
30
|
-
filterAttributesByTagName: () => filterAttributesByTagName,
|
|
31
|
-
resolveFileSource: () => resolveFileSource,
|
|
32
|
-
resolvePropValue: () => resolvePropValue
|
|
27
|
+
filterAttributesByTagName: () => filterAttributesByTagName
|
|
33
28
|
});
|
|
34
29
|
module.exports = __toCommonJS(index_exports);
|
|
35
|
-
var import_utils = require("@
|
|
30
|
+
var import_utils = require("@domql/utils");
|
|
36
31
|
const ARIA_ROLES = [
|
|
37
32
|
"alert",
|
|
38
33
|
"alertdialog",
|
|
@@ -222,15 +217,7 @@ const HTML_ATTRIBUTES = {
|
|
|
222
217
|
"type",
|
|
223
218
|
"referrerpolicy"
|
|
224
219
|
],
|
|
225
|
-
audio: [
|
|
226
|
-
"autoplay",
|
|
227
|
-
"controls",
|
|
228
|
-
"crossorigin",
|
|
229
|
-
"loop",
|
|
230
|
-
"muted",
|
|
231
|
-
"preload",
|
|
232
|
-
"src"
|
|
233
|
-
],
|
|
220
|
+
audio: [],
|
|
234
221
|
area: [
|
|
235
222
|
"alt",
|
|
236
223
|
"coords",
|
|
@@ -321,7 +308,6 @@ const HTML_ATTRIBUTES = {
|
|
|
321
308
|
"loading",
|
|
322
309
|
"marginheight",
|
|
323
310
|
"marginwidth",
|
|
324
|
-
"mozallowfullscreen",
|
|
325
311
|
"name",
|
|
326
312
|
"referrerpolicy",
|
|
327
313
|
"sandbox",
|
|
@@ -329,7 +315,6 @@ const HTML_ATTRIBUTES = {
|
|
|
329
315
|
"seamless",
|
|
330
316
|
"src",
|
|
331
317
|
"srcdoc",
|
|
332
|
-
"webkitallowfullscreen",
|
|
333
318
|
"width"
|
|
334
319
|
],
|
|
335
320
|
img: [
|
|
@@ -590,19 +575,12 @@ const HTML_ATTRIBUTES = {
|
|
|
590
575
|
"srclang"
|
|
591
576
|
],
|
|
592
577
|
video: [
|
|
593
|
-
"autoplay",
|
|
594
|
-
"controls",
|
|
595
|
-
"crossorigin",
|
|
596
|
-
"disablepictureinpicture",
|
|
597
|
-
"disableremoteplayback",
|
|
598
578
|
"height",
|
|
599
|
-
"loop",
|
|
600
|
-
"muted",
|
|
601
579
|
"playsinline",
|
|
602
580
|
"poster",
|
|
603
|
-
"
|
|
604
|
-
"
|
|
605
|
-
"
|
|
581
|
+
"width",
|
|
582
|
+
"disablepictureinpicture",
|
|
583
|
+
"disableremoteplayback"
|
|
606
584
|
],
|
|
607
585
|
svg: [
|
|
608
586
|
"className",
|
|
@@ -994,18 +972,7 @@ const DOM_EVENTS = [
|
|
|
994
972
|
"onfullscreenchange",
|
|
995
973
|
"onfullscreenerror"
|
|
996
974
|
];
|
|
997
|
-
const camelToAttr = (key) => {
|
|
998
|
-
if (key.startsWith("aria") && key.length > 4 && key.charCodeAt(4) >= 65 && key.charCodeAt(4) <= 90) {
|
|
999
|
-
return "aria-" + key.charAt(4).toLowerCase() + key.slice(5).replace(/([A-Z])/g, (m) => "-" + m.toLowerCase());
|
|
1000
|
-
}
|
|
1001
|
-
if (key.startsWith("data") && key.length > 4 && key.charCodeAt(4) >= 65 && key.charCodeAt(4) <= 90) {
|
|
1002
|
-
return "data-" + key.charAt(4).toLowerCase() + key.slice(5).replace(/([A-Z])/g, (m) => "-" + m.toLowerCase());
|
|
1003
|
-
}
|
|
1004
|
-
return null;
|
|
1005
|
-
};
|
|
1006
975
|
const checkAttributeByTagName = (tag, attribute) => {
|
|
1007
|
-
if (attribute.startsWith("aria-") || attribute.startsWith("data-")) return true;
|
|
1008
|
-
if (camelToAttr(attribute)) return true;
|
|
1009
976
|
if (Object.prototype.hasOwnProperty.call(HTML_ATTRIBUTES, tag)) {
|
|
1010
977
|
const attributes = HTML_ATTRIBUTES[tag];
|
|
1011
978
|
return attributes.includes(attribute) || attributes.includes("default");
|
|
@@ -1019,33 +986,14 @@ const checkEventFunctions = (key) => {
|
|
|
1019
986
|
const normalizedKey = key.toLowerCase();
|
|
1020
987
|
return DOM_EVENTS.includes(normalizedKey);
|
|
1021
988
|
};
|
|
1022
|
-
const filterAttributesByTagName = (tag, props
|
|
989
|
+
const filterAttributesByTagName = (tag, props) => {
|
|
1023
990
|
const filteredObject = {};
|
|
1024
991
|
for (const key in props) {
|
|
1025
992
|
if (Object.prototype.hasOwnProperty.call(props, key)) {
|
|
1026
|
-
if (cssProps && key in cssProps) continue;
|
|
1027
|
-
if (key === "aria" && props[key] && typeof props[key] === "object") {
|
|
1028
|
-
for (const ariaKey in props[key]) {
|
|
1029
|
-
if ((0, import_utils.isDefined)(props[key][ariaKey])) {
|
|
1030
|
-
filteredObject["aria-" + ariaKey] = props[key][ariaKey];
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
continue;
|
|
1034
|
-
}
|
|
1035
|
-
if (key === "data" && props[key] && typeof props[key] === "object") {
|
|
1036
|
-
for (const dataKey in props[key]) {
|
|
1037
|
-
if ((0, import_utils.isDefined)(props[key][dataKey])) {
|
|
1038
|
-
const kebab = dataKey.replace(/([A-Z])/g, (m) => "-" + m.toLowerCase());
|
|
1039
|
-
filteredObject["data-" + kebab] = props[key][dataKey];
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
continue;
|
|
1043
|
-
}
|
|
1044
993
|
const isAttribute = checkAttributeByTagName(tag, key);
|
|
1045
994
|
const isEvent = checkEventFunctions(key);
|
|
1046
995
|
if ((0, import_utils.isDefined)(props[key]) && (isAttribute || isEvent)) {
|
|
1047
|
-
|
|
1048
|
-
filteredObject[attrName] = props[key];
|
|
996
|
+
filteredObject[key] = props[key];
|
|
1049
997
|
}
|
|
1050
998
|
}
|
|
1051
999
|
}
|
|
@@ -1060,120 +1008,3 @@ const executeAttr = (elem, element) => {
|
|
|
1060
1008
|
}
|
|
1061
1009
|
return attrObj;
|
|
1062
1010
|
};
|
|
1063
|
-
const resolvePropValue = (el, value) => {
|
|
1064
|
-
let resolved = el.call("exec", value, el);
|
|
1065
|
-
if (!resolved) return;
|
|
1066
|
-
if ((0, import_utils.isString)(resolved) && resolved.includes("{{")) {
|
|
1067
|
-
resolved = el.call("replaceLiteralsWithObjectFields", resolved);
|
|
1068
|
-
}
|
|
1069
|
-
return resolved;
|
|
1070
|
-
};
|
|
1071
|
-
const resolveFileSource = (el, value) => {
|
|
1072
|
-
let src = (el.preSrc || "") + (resolvePropValue(el, value) || "");
|
|
1073
|
-
if (!src) return;
|
|
1074
|
-
try {
|
|
1075
|
-
new URL(src);
|
|
1076
|
-
return src;
|
|
1077
|
-
} catch (e) {
|
|
1078
|
-
}
|
|
1079
|
-
const { context } = el;
|
|
1080
|
-
if (!context.files && !context.assets) return src;
|
|
1081
|
-
if (src.startsWith("/assets/")) {
|
|
1082
|
-
const key = src.slice(8);
|
|
1083
|
-
const asset = context.assets && (context.assets[src] || context.assets[key]);
|
|
1084
|
-
if (asset && asset.content) return asset.content.src;
|
|
1085
|
-
return src;
|
|
1086
|
-
}
|
|
1087
|
-
if (src.startsWith("/files/")) {
|
|
1088
|
-
const key = src.slice(7);
|
|
1089
|
-
const file = context.files && (context.files[src] || context.files[key]);
|
|
1090
|
-
if (file && file.content) return file.content.src;
|
|
1091
|
-
return src;
|
|
1092
|
-
}
|
|
1093
|
-
if (context.assets) {
|
|
1094
|
-
const asset = context.assets[src];
|
|
1095
|
-
if (asset && asset.content) return asset.content.src;
|
|
1096
|
-
}
|
|
1097
|
-
if (context.files) {
|
|
1098
|
-
const file = context.files[src];
|
|
1099
|
-
if (file && file.content) return file.content.src;
|
|
1100
|
-
}
|
|
1101
|
-
return src;
|
|
1102
|
-
};
|
|
1103
|
-
const ATTR_TRANSFORMS = {
|
|
1104
|
-
src: (el) => resolveFileSource(el, el.src),
|
|
1105
|
-
href: (el) => resolvePropValue(el, el.href),
|
|
1106
|
-
action: (el) => resolvePropValue(el, el.action),
|
|
1107
|
-
poster: (el) => resolveFileSource(el, el.poster),
|
|
1108
|
-
data: (el) => resolvePropValue(el, el.data)
|
|
1109
|
-
};
|
|
1110
|
-
const applyAttrTransforms = (element) => {
|
|
1111
|
-
const tag = element.tag || "div";
|
|
1112
|
-
const result = {};
|
|
1113
|
-
for (const attr in ATTR_TRANSFORMS) {
|
|
1114
|
-
if (element[attr] !== void 0 && checkAttributeByTagName(tag, attr)) {
|
|
1115
|
-
const val = ATTR_TRANSFORMS[attr](element);
|
|
1116
|
-
if (val !== void 0) result[attr] = val;
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
return result;
|
|
1120
|
-
};
|
|
1121
|
-
const resolveCase = (caseKey, element) => {
|
|
1122
|
-
const caseFn = element.context?.cases?.[caseKey];
|
|
1123
|
-
if (caseFn === void 0) return void 0;
|
|
1124
|
-
if ((0, import_utils.isFunction)(caseFn)) return caseFn.call(element, element);
|
|
1125
|
-
return !!caseFn;
|
|
1126
|
-
};
|
|
1127
|
-
const evaluateCondition = (prefix, caseKey, element) => {
|
|
1128
|
-
if (prefix === "$") {
|
|
1129
|
-
let result = resolveCase(caseKey, element);
|
|
1130
|
-
if (result === void 0) result = !!element[caseKey];
|
|
1131
|
-
return result;
|
|
1132
|
-
}
|
|
1133
|
-
let isTruthy = element[caseKey] === true || element.state[caseKey];
|
|
1134
|
-
if (!isTruthy) {
|
|
1135
|
-
const caseResult = resolveCase(caseKey, element);
|
|
1136
|
-
if (caseResult !== void 0) isTruthy = caseResult;
|
|
1137
|
-
}
|
|
1138
|
-
return prefix === "." ? !!isTruthy : !isTruthy;
|
|
1139
|
-
};
|
|
1140
|
-
const CONDITIONAL_PREFIXES = /* @__PURE__ */ new Set(["$", ".", "!"]);
|
|
1141
|
-
const extractConditionalAttrs = (props, tag, cssProps) => {
|
|
1142
|
-
const result = {};
|
|
1143
|
-
const addConditionalAttr = (attrName, attrVal, prefix, caseKey) => {
|
|
1144
|
-
const capturedVal = attrVal;
|
|
1145
|
-
result[attrName] = (el) => {
|
|
1146
|
-
if (!evaluateCondition(prefix, caseKey, el)) return void 0;
|
|
1147
|
-
return (0, import_utils.isFunction)(capturedVal) ? capturedVal(el) : capturedVal;
|
|
1148
|
-
};
|
|
1149
|
-
};
|
|
1150
|
-
for (const key in props) {
|
|
1151
|
-
const prefix = key.charAt(0);
|
|
1152
|
-
if (!CONDITIONAL_PREFIXES.has(prefix)) continue;
|
|
1153
|
-
const block = props[key];
|
|
1154
|
-
if (!block || typeof block !== "object") continue;
|
|
1155
|
-
const caseKey = key.slice(1);
|
|
1156
|
-
for (const attrKey in block) {
|
|
1157
|
-
if (cssProps && attrKey in cssProps) continue;
|
|
1158
|
-
if (attrKey === "aria" && block[attrKey] && typeof block[attrKey] === "object") {
|
|
1159
|
-
for (const ariaKey in block[attrKey]) {
|
|
1160
|
-
addConditionalAttr("aria-" + ariaKey, block[attrKey][ariaKey], prefix, caseKey);
|
|
1161
|
-
}
|
|
1162
|
-
continue;
|
|
1163
|
-
}
|
|
1164
|
-
if (attrKey === "data" && block[attrKey] && typeof block[attrKey] === "object") {
|
|
1165
|
-
for (const dataKey in block[attrKey]) {
|
|
1166
|
-
const kebab = dataKey.replace(/([A-Z])/g, (m) => "-" + m.toLowerCase());
|
|
1167
|
-
addConditionalAttr("data-" + kebab, block[attrKey][dataKey], prefix, caseKey);
|
|
1168
|
-
}
|
|
1169
|
-
continue;
|
|
1170
|
-
}
|
|
1171
|
-
const isAttribute = checkAttributeByTagName(tag, attrKey);
|
|
1172
|
-
const isEvent = checkEventFunctions(attrKey);
|
|
1173
|
-
if (!isAttribute && !isEvent) continue;
|
|
1174
|
-
const attrName = camelToAttr(attrKey) || attrKey;
|
|
1175
|
-
addConditionalAttr(attrName, block[attrKey], prefix, caseKey);
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
return result;
|
|
1179
|
-
};
|
package/index.js
CHANGED
|
@@ -1057,13 +1057,19 @@ export const checkAttributeByTagName = (tag, attribute) => {
|
|
|
1057
1057
|
// camelCase aria/data attrs
|
|
1058
1058
|
if (camelToAttr(attribute)) return true
|
|
1059
1059
|
|
|
1060
|
+
// Global attributes (`title`, `id`, `class`, `role`, `tabindex`, `hidden`,
|
|
1061
|
+
// `lang`, `dir`, `draggable`, `contenteditable`, `spellcheck`, `slot`, …)
|
|
1062
|
+
// apply to every tag. Prior behavior only consulted HTML_ATTRIBUTES.default
|
|
1063
|
+
// for tags WITHOUT a per-tag list, which silently dropped global attrs on
|
|
1064
|
+
// every typed tag (button/a/img/input/...). Always allow defaults first,
|
|
1065
|
+
// then tag-specific extras.
|
|
1066
|
+
if (HTML_ATTRIBUTES.default.includes(attribute)) return true
|
|
1067
|
+
|
|
1060
1068
|
if (Object.prototype.hasOwnProperty.call(HTML_ATTRIBUTES, tag)) {
|
|
1061
1069
|
const attributes = HTML_ATTRIBUTES[tag]
|
|
1062
|
-
return attributes.includes(attribute)
|
|
1063
|
-
} else {
|
|
1064
|
-
const defaultAttributes = HTML_ATTRIBUTES.default
|
|
1065
|
-
return defaultAttributes.includes(attribute)
|
|
1070
|
+
return attributes.includes(attribute)
|
|
1066
1071
|
}
|
|
1072
|
+
return false
|
|
1067
1073
|
}
|
|
1068
1074
|
|
|
1069
1075
|
export const checkEventFunctions = (key) => {
|
|
@@ -1080,6 +1086,11 @@ export const filterAttributesByTagName = (tag, props, cssProps) => {
|
|
|
1080
1086
|
if (cssProps && key in cssProps) continue
|
|
1081
1087
|
|
|
1082
1088
|
// aria: { label: 'foo', expanded: true } → aria-label, aria-expanded
|
|
1089
|
+
// Function values are stored as-is here; `executeAttr` is the single
|
|
1090
|
+
// place that resolves reactive (el, state) → string for HTML attrs.
|
|
1091
|
+
// We funnel aria/data through `attr` instead of duplicating execution
|
|
1092
|
+
// logic so v3.14 reactive aria/data attributes work with the same
|
|
1093
|
+
// re-render cycle as `attr.foo` — see FA-L1.
|
|
1083
1094
|
if (key === 'aria' && props[key] && typeof props[key] === 'object') {
|
|
1084
1095
|
for (const ariaKey in props[key]) {
|
|
1085
1096
|
if (isDefined(props[key][ariaKey])) {
|
|
@@ -1119,6 +1130,29 @@ export const executeAttr = (elem, element) => {
|
|
|
1119
1130
|
attrObj[attrProp] = elem.attr[attrProp](element, element.state, element.context)
|
|
1120
1131
|
}
|
|
1121
1132
|
}
|
|
1133
|
+
// FA-L1: aria.X and data.X with FUNCTION values must execute the same way
|
|
1134
|
+
// as attr.X. Without this, `aria: { label: (el, s) => s.text }` writes a
|
|
1135
|
+
// function reference to the DOM attribute and renders as `null`.
|
|
1136
|
+
// Static (non-function) aria/data values are already promoted to flat
|
|
1137
|
+
// attributes by `filterAttributesByTagName`; we only handle functions
|
|
1138
|
+
// here to avoid double-write.
|
|
1139
|
+
if (elem.aria && typeof elem.aria === 'object') {
|
|
1140
|
+
for (const ariaKey in elem.aria) {
|
|
1141
|
+
const v = elem.aria[ariaKey]
|
|
1142
|
+
if (typeof v === 'function') {
|
|
1143
|
+
attrObj['aria-' + ariaKey] = v(element, element.state, element.context)
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
if (elem.data && typeof elem.data === 'object') {
|
|
1148
|
+
for (const dataKey in elem.data) {
|
|
1149
|
+
const v = elem.data[dataKey]
|
|
1150
|
+
if (typeof v === 'function') {
|
|
1151
|
+
const kebab = dataKey.replace(/([A-Z])/g, (m) => '-' + m.toLowerCase())
|
|
1152
|
+
attrObj['data-' + kebab] = v(element, element.state, element.context)
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1122
1156
|
return attrObj
|
|
1123
1157
|
}
|
|
1124
1158
|
|
package/package.json
CHANGED