@optionfactory/fml 9.0.0-rc1 → 9.0.0-rc2

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/ful.mjs CHANGED
@@ -1025,6 +1025,7 @@ class Form extends ParsedElement {
1025
1025
  'response-mapper',
1026
1026
  'clear-invalid-on-change:presence',
1027
1027
  'scroll-on-error:presence',
1028
+ 'autocomplete',
1028
1029
  ];
1029
1030
  form;
1030
1031
  render() {
@@ -1035,6 +1036,10 @@ class Form extends ParsedElement {
1035
1036
  //internals messages custom elements have no default UI for
1036
1037
  form.setAttribute('novalidate', '');
1037
1038
  Attributes.forward('form-', this, form);
1039
+ //the fields read it off whichever of the two they reach first, which depends
1040
+ //on whether they upgraded before or after this render: they cannot read it
1041
+ //off their own control, which carries form="" and so has no form owner
1042
+ Attributes.set(form, 'autocomplete', this.declared('autocomplete'));
1038
1043
  form.replaceChildren(...this.childNodes);
1039
1044
  form.addEventListener('submit', async (e) => {
1040
1045
  e.preventDefault();
@@ -1239,6 +1244,22 @@ const compiled = (attr, pattern) =>
1239
1244
  * `reject="[^0-9]"` both leave the digits. Keeping is the one worth reaching for,
1240
1245
  * the rejecting spelling of an allowed set being a double negative.
1241
1246
  */
1247
+ /**
1248
+ * The autofill token a field inherits from the form around it.
1249
+ *
1250
+ * A control is rendered with `form=""` so that the host is the only thing that
1251
+ * submits, which also leaves it without a form owner, and the platform resolves
1252
+ * `autocomplete` through the form owner. So a form declaring it reaches nothing
1253
+ * on its own and the field reads the setting off the form element instead.
1254
+ *
1255
+ * The `form` a `ful-form` renders answers here, the host copying its token onto
1256
+ * it, and a plain `form` around ful fields answers too: the platform meant the
1257
+ * same thing by it, and its inheritance is broken here for the same reason. An
1258
+ * ancestor always upgrades before its descendants, so the rendered form is in
1259
+ * place by the time a field of its own builds.
1260
+ */
1261
+ const inheritedAutocomplete = (el) => el.closest('form')?.getAttribute('autocomplete') ?? null;
1262
+
1242
1263
  const warnedBoth = new WeakSet();
1243
1264
  const filterOf = (el) => {
1244
1265
  const keep = el.declared('keep');
@@ -1266,7 +1287,15 @@ class Input extends Field {
1266
1287
  static observed = ['placeholder'];
1267
1288
  //configuration: the control is built from them and the value getter reads them,
1268
1289
  //but none of them is meant to change once the element is up
1269
- static attributes = ['type', 'v-type', 'keep', 'reject', 'uppercase:presence', 'trim:presence'];
1290
+ static attributes = [
1291
+ 'type',
1292
+ 'v-type',
1293
+ 'keep',
1294
+ 'reject',
1295
+ 'uppercase:presence',
1296
+ 'trim:presence',
1297
+ 'autocomplete',
1298
+ ];
1270
1299
  static slots = true;
1271
1300
  static template = `
1272
1301
  <label>{{{{ slots.default }}}}</label>
@@ -1290,6 +1319,14 @@ class Input extends Field {
1290
1319
  const fragment = this.template().withOverlay({ type, slots }).render();
1291
1320
  this._input = fragment.querySelector('input,textarea');
1292
1321
 
1322
+ //the browser reads autocomplete off the control it is classifying, so the
1323
+ //field's own token, or the form's where it declares none, is put there.
1324
+ //Set before the passthrough, which stays the last word
1325
+ Attributes.set(
1326
+ this._input,
1327
+ 'autocomplete',
1328
+ this.declared('autocomplete') ?? inheritedAutocomplete(this),
1329
+ );
1293
1330
  Attributes.forward('input-', this, this._input);
1294
1331
  this._input.addEventListener('input', (evt) => {
1295
1332
  const strip = filterOf(this);