octane 0.2.3 → 0.2.4

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/css.cjs CHANGED
@@ -20,6 +20,7 @@ var css_exports = {};
20
20
  __export(css_exports, {
21
21
  devWarnStyleCoercion: () => devWarnStyleCoercion,
22
22
  devWarnStyleProperty: () => devWarnStyleProperty,
23
+ mergeClass: () => mergeClass,
23
24
  normalizeClass: () => normalizeClass,
24
25
  styleName: () => styleName
25
26
  });
@@ -47,6 +48,13 @@ function normalizeClass(value) {
47
48
  }
48
49
  return str;
49
50
  }
51
+ function mergeClass(left, right) {
52
+ const a = normalizeClass(left);
53
+ const b = normalizeClass(right);
54
+ if (!a) return b;
55
+ if (!b) return a;
56
+ return a + " " + b;
57
+ }
50
58
  const styleNameCache = /* @__PURE__ */ new Map();
51
59
  function styleName(name) {
52
60
  const cached = styleNameCache.get(name);
@@ -111,6 +119,7 @@ function devWarnStyleCoercion(name, value) {
111
119
  0 && (module.exports = {
112
120
  devWarnStyleCoercion,
113
121
  devWarnStyleProperty,
122
+ mergeClass,
114
123
  normalizeClass,
115
124
  styleName
116
125
  });
@@ -453,8 +453,13 @@ for (const base of [
453
453
  UNITLESS_STYLE_PROPS.add("moz" + c);
454
454
  UNITLESS_STYLE_PROPS.add("o" + c);
455
455
  }
456
+ const unitlessStylePropCache = /* @__PURE__ */ new Map();
456
457
  function isUnitlessStyleProp(name) {
457
- return UNITLESS_STYLE_PROPS.has(name.replaceAll("-", "").toLowerCase());
458
+ const cached = unitlessStylePropCache.get(name);
459
+ if (cached !== void 0) return cached;
460
+ const result = UNITLESS_STYLE_PROPS.has(name.replaceAll("-", "").toLowerCase());
461
+ unitlessStylePropCache.set(name, result);
462
+ return result;
458
463
  }
459
464
  function cssStyleValue(name, value) {
460
465
  if (typeof value === "number" && value !== 0 && name.charCodeAt(0) !== 45 && !isUnitlessStyleProp(name)) {
@@ -1724,12 +1724,17 @@ function journalDefaultValue(input) {
1724
1724
  journalAttr(input, "value");
1725
1725
  }
1726
1726
  }
1727
+ function radioCousins(input) {
1728
+ if (input.form !== null) return input.form.elements;
1729
+ const root = input.getRootNode();
1730
+ return root.nodeType === 9 ? root.getElementsByName(input.name) : root.querySelectorAll('input[type="radio"]');
1731
+ }
1727
1732
  function journalRadioCousins(input) {
1728
1733
  const name = input.name;
1729
- const group = input.form !== null ? input.form.elements : typeof document !== "undefined" ? document.getElementsByName(name) : [];
1734
+ const group = radioCousins(input);
1730
1735
  for (let i = 0; i < group.length; i++) {
1731
1736
  const other = group[i];
1732
- if (other === input || !other.checked || other.localName !== "input" || other.type !== "radio" || other.name !== name) {
1737
+ if (other === input || !other.checked || other.localName !== "input" || other.type !== "radio" || other.name !== name || other.form !== input.form) {
1733
1738
  continue;
1734
1739
  }
1735
1740
  TRANSITION_JOURNAL.push(JOURNAL_PROP, other, "checked", true);
@@ -10053,8 +10058,9 @@ function normalizedHostProp(el, rawName) {
10053
10058
  }
10054
10059
  function setHostPropSources(el, sources, prev, scope, hasNestedChildren = false) {
10055
10060
  const props = /* @__PURE__ */ new Map();
10061
+ let classMerges = null;
10056
10062
  let sourceOrder = 0;
10057
- const record = (rawName, value) => {
10063
+ function record(rawName, value) {
10058
10064
  if (typeof rawName !== "string") return;
10059
10065
  const order = sourceOrder++;
10060
10066
  const previous = props.get(rawName);
@@ -10064,10 +10070,15 @@ function setHostPropSources(el, sources, prev, scope, hasNestedChildren = false)
10064
10070
  firstOrder: previous?.firstOrder ?? order,
10065
10071
  lastOrder: order
10066
10072
  });
10067
- };
10073
+ }
10068
10074
  for (const source of sources) {
10069
10075
  if (!source[0]) {
10070
- record(source[1], source[2]);
10076
+ const rawName = source[1];
10077
+ if (source[3] === true && typeof rawName === "string" && (rawName === "class" || rawName === "className")) {
10078
+ (classMerges ??= []).push({ rawName, value: source[2], order: sourceOrder++ });
10079
+ continue;
10080
+ }
10081
+ record(rawName, source[2]);
10071
10082
  continue;
10072
10083
  }
10073
10084
  const spread = source[1];
@@ -10093,6 +10104,22 @@ function setHostPropSources(el, sources, prev, scope, hasNestedChildren = false)
10093
10104
  writer.lastOrder
10094
10105
  ]);
10095
10106
  }
10107
+ if (classMerges !== null) {
10108
+ for (const extra of classMerges) {
10109
+ const [identity, name] = normalizedHostProp(el, extra.rawName);
10110
+ const previous = values.get(identity);
10111
+ if (previous !== void 0) {
10112
+ values.set(identity, [
10113
+ previous[0],
10114
+ (0, import_css.mergeClass)(previous[1], extra.value),
10115
+ previous[2],
10116
+ extra.order
10117
+ ]);
10118
+ continue;
10119
+ }
10120
+ values.set(identity, [name, extra.value, extra.order, extra.order]);
10121
+ }
10122
+ }
10096
10123
  const resolved = /* @__PURE__ */ Object.create(null);
10097
10124
  const ordered = [...values.values()];
10098
10125
  if (needsWinningOrderSort) ordered.sort((a, b) => a[2] - b[2]);
@@ -10268,11 +10295,12 @@ function headBlock(scope, slot, key, tag, attrs, text) {
10268
10295
  const ownerDocument = parent.nodeType === 9 ? parent : parent.ownerDocument;
10269
10296
  const head = ownerDocument.head;
10270
10297
  let el2 = adoptServerHeadEl(head, (0, import_head_ownership.headOwnershipKey)(key, rootIdentifierPrefix(scope.block)), tag);
10298
+ const adopted = el2 !== null;
10271
10299
  if (el2 === null) {
10272
10300
  el2 = ownerDocument.createElement(tag);
10273
10301
  head.appendChild(el2);
10274
10302
  }
10275
- state = { el: el2 };
10303
+ state = { el: el2, attrNames: adopted ? el2.getAttributeNames() : void 0 };
10276
10304
  scope.slots[slot] = state;
10277
10305
  (scope.cleanups ??= []).push(() => {
10278
10306
  removeHeadEventListeners(state, null);
@@ -10281,8 +10309,20 @@ function headBlock(scope, slot, key, tag, attrs, text) {
10281
10309
  });
10282
10310
  }
10283
10311
  const el = state.el;
10312
+ if (TRANSITION_JOURNAL !== null) {
10313
+ journalObjectOnce(state);
10314
+ journalBag();
10315
+ }
10284
10316
  if (state.handlers !== void 0) removeHeadEventListeners(state, attrs);
10317
+ const previousNames = state.attrNames;
10318
+ if (previousNames !== void 0) {
10319
+ for (let i = 0; i < previousNames.length; i++) {
10320
+ const name = previousNames[i];
10321
+ if (attrs === null || !(name in attrs)) setAttribute(el, name, null);
10322
+ }
10323
+ }
10285
10324
  if (attrs !== null) {
10325
+ const names = [];
10286
10326
  for (const k in attrs) {
10287
10327
  const ev = k.length > 2 && k[0] === "o" && k[1] === "n" ? eventSlot(k) : null;
10288
10328
  if (ev !== null) {
@@ -10303,12 +10343,19 @@ function headBlock(scope, slot, key, tag, attrs, text) {
10303
10343
  }
10304
10344
  continue;
10305
10345
  }
10346
+ names.push(k);
10306
10347
  setAttribute(el, k, attrs[k]);
10307
10348
  }
10349
+ state.attrNames = names;
10350
+ } else {
10351
+ state.attrNames = void 0;
10308
10352
  }
10309
- if (text != null) {
10310
- const t = String(text);
10311
- if (el.textContent !== t) el.textContent = t;
10353
+ if (text != null || tag === "title") {
10354
+ const t = text == null ? "" : String(text);
10355
+ if (el.textContent !== t) {
10356
+ if (TRANSITION_JOURNAL !== null) journalRootRange(el, null, null);
10357
+ el.textContent = t;
10358
+ }
10312
10359
  }
10313
10360
  }
10314
10361
  function namespaceHead(props, scope) {
@@ -10341,8 +10388,21 @@ function namespaceHeadElement(headKey, tag, attrs, text, authoredKey) {
10341
10388
  return createElement(namespaceHead, config);
10342
10389
  }
10343
10390
  function injectStyle(id, css, nonce) {
10391
+ if (typeof document === "undefined") {
10392
+ _injectedStyles.add(id);
10393
+ return;
10394
+ }
10395
+ const existing = document.querySelector(`style[data-octane="${id}"]`);
10396
+ if (existing !== null) {
10397
+ if (_injectedStyles.has(id)) {
10398
+ if (existing.textContent !== css) existing.textContent = css;
10399
+ } else {
10400
+ _injectedStyles.add(id);
10401
+ }
10402
+ return;
10403
+ }
10344
10404
  if (_injectedStyles.has(id)) return;
10345
- if (typeof document !== "undefined" && document.querySelector(`style[data-octane="${id}"], style[data-href="octane-${id}"]`)) {
10405
+ if (document.querySelector(`style[data-href~="octane-${id}"]`)) {
10346
10406
  _injectedStyles.add(id);
10347
10407
  return;
10348
10408
  }
@@ -11370,13 +11430,12 @@ function armControlledBase(el) {
11370
11430
  sv: null,
11371
11431
  sawV: false,
11372
11432
  sawC: false,
11433
+ sawDC: false,
11373
11434
  dvv: UNCONTROLLED,
11374
11435
  composing: false,
11375
11436
  compositionEndTask: void 0,
11376
11437
  queued: false,
11377
11438
  formSeen: false,
11378
- formDefaultValue: UNCONTROLLED,
11379
- formDefaultChecked: UNCONTROLLED,
11380
11439
  formMultiple: false
11381
11440
  };
11382
11441
  el.$$ctrl = ctrl;
@@ -11551,9 +11610,14 @@ function setCheckedState(input, value, ctrl) {
11551
11610
  if (process.env.NODE_ENV !== "production")
11552
11611
  queueDevFormDiagnostic(input, CURRENT_SCOPE ?? void 0);
11553
11612
  const hydration = activeHydration();
11554
- if (hydration !== null && !hydration.isFresh(input)) return;
11555
- if (input.checked !== b) input.checked = b;
11613
+ if (hydration !== null && !hydration.isFresh(input)) {
11614
+ input.checked = input.checked;
11615
+ ctrl.sawDC = true;
11616
+ return;
11617
+ }
11618
+ input.checked = b;
11556
11619
  input.defaultChecked = b;
11620
+ ctrl.sawDC = true;
11557
11621
  return;
11558
11622
  }
11559
11623
  if (process.env.NODE_ENV !== "production" && ctrl.c === -1) devWarnControlledFlip(input, true);
@@ -11567,7 +11631,7 @@ function inActivationWindow(input) {
11567
11631
  const target = activationCheckable;
11568
11632
  if (target === null) return false;
11569
11633
  if (input === target) return true;
11570
- return input.type === "radio" && target.type === "radio" && input.name !== "" && input.name === target.name && input.form === target.form;
11634
+ return input.type === "radio" && target.type === "radio" && input.name !== "" && input.name === target.name && input.form === target.form && (input.form !== null || input.getRootNode() === target.getRootNode());
11571
11635
  }
11572
11636
  function setChecked(el, value) {
11573
11637
  const ctrl = armControlled(el);
@@ -11705,6 +11769,7 @@ function setDefaultValue(el, value, initial) {
11705
11769
  }
11706
11770
  }
11707
11771
  const DEFAULT_VALUE_BASELINE = /* @__PURE__ */ Symbol("octane.defaultValue");
11772
+ const DEFAULT_CHECKED_INITIALIZED = /* @__PURE__ */ Symbol("octane.defaultCheckedInitialized");
11708
11773
  function setDefaultValueUncontrolled(el, value) {
11709
11774
  const hydration = activeHydration();
11710
11775
  const input = el;
@@ -11733,10 +11798,30 @@ function setDefaultValueUncontrolled(el, value) {
11733
11798
  }
11734
11799
  function setDefaultChecked(el, value) {
11735
11800
  const ctrl = armControlled(el);
11801
+ const input = el;
11736
11802
  const hydration = activeHydration();
11737
- if (hydration !== null && !hydration.isFresh(el) || value == null) return;
11803
+ const hydrating = hydration !== null && !hydration.isFresh(el);
11804
+ const first = !ctrl.sawDC;
11805
+ if (first) {
11806
+ if (TRANSITION_JOURNAL !== null) {
11807
+ journalObjectOnce(ctrl);
11808
+ journalBag();
11809
+ }
11810
+ ctrl.sawDC = true;
11811
+ }
11812
+ if (hydrating) {
11813
+ if (first) input.checked = input.checked;
11814
+ return;
11815
+ }
11738
11816
  if (ctrl.c !== -1) return;
11739
- const input = el;
11817
+ if (first && !(DEFAULT_CHECKED_INITIALIZED in input)) {
11818
+ if (TRANSITION_JOURNAL !== null) {
11819
+ TRANSITION_JOURNAL.push(JOURNAL_PROP, input, "checked", input.checked);
11820
+ if (input.type === "radio" && input.name !== "" && !!value) journalRadioCousins(input);
11821
+ }
11822
+ input.checked = value == null ? input.checked : !!value;
11823
+ }
11824
+ if (value == null) return;
11740
11825
  const b = !!value;
11741
11826
  if (input.defaultChecked !== b) {
11742
11827
  if (TRANSITION_JOURNAL !== null) {
@@ -11795,15 +11880,12 @@ function setFormControlSources(el, sources) {
11795
11880
  }
11796
11881
  const ctrl = armControlled(el);
11797
11882
  const first = !ctrl.formSeen;
11798
- const previousDefaultChecked = ctrl.formDefaultChecked;
11799
11883
  const previousMultiple = ctrl.formMultiple;
11800
11884
  if (TRANSITION_JOURNAL !== null) {
11801
11885
  journalObjectOnce(ctrl);
11802
11886
  journalBag();
11803
11887
  }
11804
11888
  ctrl.formSeen = true;
11805
- ctrl.formDefaultValue = defaultValue;
11806
- ctrl.formDefaultChecked = defaultChecked;
11807
11889
  if (process.env.NODE_ENV !== "production" && hasDevFormDiagnosticContext(el, CURRENT_SCOPE ?? void 0)) {
11808
11890
  const diagnostic = ensureDevFormDiagnosticState(el);
11809
11891
  diagnostic.authoringProps = { value, defaultValue, checked, defaultChecked, multiple };
@@ -11819,10 +11901,8 @@ function setFormControlSources(el, sources) {
11819
11901
  setDefaultValue(input, defaultString, first);
11820
11902
  }
11821
11903
  setChecked(input, checked);
11822
- if (checked == null && defaultChecked != null) setDefaultChecked(input, defaultChecked);
11823
- if (!first && defaultChecked == null && previousDefaultChecked !== UNCONTROLLED && previousDefaultChecked != null) {
11824
- input.defaultChecked = false;
11825
- }
11904
+ if (checked == null && (defaultChecked != null || first))
11905
+ setDefaultChecked(input, defaultChecked);
11826
11906
  return;
11827
11907
  }
11828
11908
  if (tag === "textarea") {
@@ -12015,10 +12095,10 @@ function restoreCheckedState(input, ctrl) {
12015
12095
  }
12016
12096
  function restoreRadioCousins(input) {
12017
12097
  const name = input.name;
12018
- const group = input.form !== null ? input.form.elements : typeof document !== "undefined" ? document.getElementsByName(name) : [];
12098
+ const group = radioCousins(input);
12019
12099
  for (let i = 0; i < group.length; i++) {
12020
12100
  const other = group[i];
12021
- if (other === input || other.localName !== "input" || other.type !== "radio" || other.name !== name) {
12101
+ if (other === input || other.localName !== "input" || other.type !== "radio" || other.name !== name || other.form !== input.form) {
12022
12102
  continue;
12023
12103
  }
12024
12104
  const octrl = other.$$ctrl;
@@ -13494,19 +13574,29 @@ function hasDangerHTML(props) {
13494
13574
  function hasHostPropContent(descriptor) {
13495
13575
  return hasDangerHTML(descriptor.props) || descriptor.type === "textarea" && (descriptor.props?.value != null || descriptor.props?.defaultValue != null);
13496
13576
  }
13577
+ function markInputCheckedness(input) {
13578
+ input.checked = input.checked;
13579
+ input[DEFAULT_CHECKED_INITIALIZED] = true;
13580
+ }
13497
13581
  function applyDeoptProps(el, props, ownerBlock) {
13498
13582
  if (props == null) {
13583
+ if (el.localName === "input") markInputCheckedness(el);
13499
13584
  if (process.env.NODE_ENV !== "production") queueDevFormDiagnostic(el, ownerBlock);
13500
13585
  return;
13501
13586
  }
13587
+ let needsCheckedInitialization = el.localName === "input";
13502
13588
  for (const name in props) {
13503
13589
  if (name === "key" || name === "children") continue;
13504
13590
  if (name === "suppressHydrationWarning") {
13505
13591
  el.__oct_suppress = props[name] === true;
13506
13592
  continue;
13507
13593
  }
13508
- applyDeoptProp(el, name, props[name], ownerBlock);
13594
+ const value = props[name];
13595
+ if (needsCheckedInitialization && (name === "defaultChecked" || name === "checked" && value != null))
13596
+ needsCheckedInitialization = false;
13597
+ applyDeoptProp(el, name, value, ownerBlock);
13509
13598
  }
13599
+ if (needsCheckedInitialization) markInputCheckedness(el);
13510
13600
  if (process.env.NODE_ENV !== "production") queueDevFormDiagnostic(el, ownerBlock);
13511
13601
  }
13512
13602
  function patchDeoptProps(el, prevProps, nextProps, ownerBlock) {
@@ -13567,6 +13657,7 @@ function hostComponent(scope, slot, tag, props, childrenBody, anchor) {
13567
13657
  }
13568
13658
  function applyHostProps(el, props, scope, state) {
13569
13659
  const prev = state.props;
13660
+ let needsCheckedInitialization = prev === void 0 && el.localName === "input";
13570
13661
  if (ROOT_RENDER_TRANSACTION !== null && prev !== props) journalObjectOnce(state);
13571
13662
  if (prev != null) {
13572
13663
  for (const k in prev) {
@@ -13584,12 +13675,15 @@ function applyHostProps(el, props, scope, state) {
13584
13675
  }
13585
13676
  state.props = props;
13586
13677
  if (props == null) {
13678
+ if (needsCheckedInitialization) markInputCheckedness(el);
13587
13679
  if (process.env.NODE_ENV !== "production") queueDevFormDiagnostic(el, scope);
13588
13680
  return;
13589
13681
  }
13590
13682
  for (const name in props) {
13591
13683
  if (name === "key" || name === "children") continue;
13592
13684
  const v = props[name];
13685
+ if (needsCheckedInitialization && (name === "defaultChecked" || name === "checked" && v != null))
13686
+ needsCheckedInitialization = false;
13593
13687
  const actionName = formActionAttributeName(el, name);
13594
13688
  if (actionName !== null) {
13595
13689
  setFormAction(el, actionName, v, prev?.[name]);
@@ -13627,6 +13721,7 @@ function applyHostProps(el, props, scope, state) {
13627
13721
  }
13628
13722
  }
13629
13723
  }
13724
+ if (needsCheckedInitialization) markInputCheckedness(el);
13630
13725
  if (process.env.NODE_ENV !== "production") queueDevFormDiagnostic(el, scope);
13631
13726
  }
13632
13727
  const DEOPT_DESC = /* @__PURE__ */ Symbol("octane.deoptDesc");