@neeloong/form 0.2.0 → 0.4.0

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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @neeloong/form v0.2.0
2
+ * @neeloong/form v0.4.0
3
3
  * (c) 2024-2025 Fierflame
4
4
  * @license Apache-2.0
5
5
  */
@@ -855,8 +855,8 @@ class ArrayStore extends Store {
855
855
  }
856
856
 
857
857
  const errors = {
858
- CALC: 'no `creteCalc` option, no expression parsing support',
859
- EVENT: 'no `creteEvent`, options, no event parsing support',
858
+ CALC: 'no `createCalc` option, no expression parsing support',
859
+ EVENT: 'no `createEvent`, options, no event parsing support',
860
860
  /** @param {string} endTag @param {string} startTag */
861
861
  CLOSE: (endTag, startTag) => `end tag name: ${endTag} is not match the current start tagName: ${startTag}`,
862
862
  /** @param {string} name */
@@ -900,15 +900,15 @@ class ParseError extends Error {
900
900
 
901
901
  /** @import * as Layout from './index.mjs' */
902
902
 
903
- const attrPattern = /^(?<decorator>[:@!+*\.]|style:|样式:)?(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*)$/u;
903
+ const attrPattern = /^(?<decorator>[:@!+*\.?]|style:|样式:)?(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*)$/u;
904
904
  const nameRegex = /^(?<name>[a-zA-Z$\p{Unified_Ideograph}_][\da-zA-Z$\p{Unified_Ideograph}_]*)?$/u;
905
905
  /**
906
906
  * @param {Layout.Node} node
907
- * @param {Exclude<Layout.Options['creteCalc'], undefined>} creteCalc
908
- * @param {Exclude<Layout.Options['creteEvent'], undefined>} creteEvent
907
+ * @param {Exclude<Layout.Options['createCalc'], undefined>} createCalc
908
+ * @param {Exclude<Layout.Options['createEvent'], undefined>} createEvent
909
909
  */
910
- function createAttributeAdder(node, creteCalc, creteEvent) {
911
- const { attrs, directives, events, classes, styles, vars, aliases } = node;
910
+ function createAttributeAdder(node, createCalc, createEvent) {
911
+ const { attrs, directives, events, classes, styles, vars, aliases, params } = node;
912
912
  /**
913
913
  * @param {string} qName
914
914
  * @param {string} value
@@ -928,37 +928,36 @@ function createAttributeAdder(node, creteCalc, creteEvent) {
928
928
  if (!decorator) {
929
929
  attrs[name] = value;
930
930
  } else if (decorator === ':') {
931
- attrs[name] = nameRegex.test(value) ? {name: value} : creteCalc(value);
931
+ attrs[name] = nameRegex.test(value) ? {name: value} : createCalc(value);
932
932
  } else if (decorator === '.') {
933
- classes[name] = !value ? true : nameRegex.test(value) ? value : creteCalc(value);
933
+ classes[name] = !value ? true : nameRegex.test(value) ? value : createCalc(value);
934
934
  } else if (decorator === 'style:') {
935
- styles[name] = nameRegex.test(value) ? value : creteCalc(value);
935
+ styles[name] = nameRegex.test(value) ? value : createCalc(value);
936
936
  } else if (decorator === '@') {
937
- events[name] = nameRegex.test(value) ? value : creteEvent(value);
937
+ events[name] = nameRegex.test(value) ? value : createEvent(value);
938
938
  } else if (decorator === '+') {
939
- vars[name] = !value ? '' : nameRegex.test(value) ? value : creteCalc(value);
939
+ vars[name] = !value ? '' : nameRegex.test(value) ? value : createCalc(value);
940
940
  } else if (decorator === '*') {
941
- aliases[name] = nameRegex.test(value) ? value : creteCalc(value);
941
+ aliases[name] = nameRegex.test(value) ? value : createCalc(value);
942
+ } else if (decorator === '?') {
943
+ params[name] = nameRegex.test(value) ? value : createCalc(value);
942
944
  } else if (decorator === '!') {
943
945
  const key = name.toString();
944
946
  switch (key) {
945
- case 'fragment':
946
- case 'else':
947
- directives[key] = true;
948
- break;
947
+ case 'fragment': directives.fragment = value || true; break;
948
+ case 'else': directives.else = true; break;
949
949
  case 'enum':
950
- directives.enum = value ? nameRegex.test(value) ? value : creteCalc(value) : true;
950
+ directives.enum = value ? nameRegex.test(value) ? value : createCalc(value) : true;
951
951
  break;
952
952
  case 'if':
953
953
  case 'text':
954
954
  case 'html':
955
- directives[key] = nameRegex.test(value) ? value : creteCalc(value);
956
- break;
957
- case 'bind':
958
- case 'value':
959
- case 'comment':
960
- directives[key] = value;
955
+ directives[key] = nameRegex.test(value) ? value : createCalc(value);
961
956
  break;
957
+ case 'template': directives.template = value; break;
958
+ case 'bind': directives.bind = value || true; break;
959
+ case 'value': directives.value = value; break;
960
+ case 'comment': directives.comment = value; break;
962
961
  }
963
962
  }
964
963
  }
@@ -985,6 +984,7 @@ function createElement(name, is) {
985
984
  styles: Object.create(null),
986
985
  vars: Object.create(null),
987
986
  aliases: Object.create(null),
987
+ params: Object.create(null),
988
988
  };
989
989
  }
990
990
 
@@ -1303,8 +1303,8 @@ function entityReplacer(a) {
1303
1303
  * @returns {(Layout.Node | string)[]}
1304
1304
  */
1305
1305
  function parse(source, {
1306
- creteCalc = () => { throw new ParseError('CALC'); },
1307
- creteEvent = () => { throw new ParseError('EVENT'); },
1306
+ createCalc = () => { throw new ParseError('CALC'); },
1307
+ createEvent = () => { throw new ParseError('EVENT'); },
1308
1308
  simpleTag = new Set,
1309
1309
  } = {}) {
1310
1310
  /** @type {(Layout.Node | string)[]} */
@@ -1424,7 +1424,7 @@ function parse(source, {
1424
1424
  currentNode = createElement(tagRes.name, tagRes.is);
1425
1425
  current.children.push(currentNode);
1426
1426
  current = currentNode;
1427
- const addAttribute = createAttributeAdder(currentNode, creteCalc, creteEvent);
1427
+ const addAttribute = createAttributeAdder(currentNode, createCalc, createEvent);
1428
1428
 
1429
1429
  let run = true;
1430
1430
  let closed = false;
@@ -1503,13 +1503,21 @@ function _xmlEncoder(c) {
1503
1503
  * @returns {Iterable<string>}
1504
1504
  */
1505
1505
  function* nodeToString(node, level = 0) {
1506
- const { attrs, events, directives, children, is, name, classes, styles, aliases, vars } = node;
1506
+ const { attrs, events, directives, children, is, name, params, classes, styles, aliases, vars } = node;
1507
1507
  const pad = level > 0 ? ''.padEnd(level, '\t') : '';
1508
1508
 
1509
1509
  yield pad;
1510
1510
  yield* ['<', name || '-'];
1511
1511
  if (is) { yield* ['|', is]; }
1512
1512
 
1513
+ for (const [name, value] of Object.entries(params)) {
1514
+ if (value == null) { continue; }
1515
+ const val = typeof value === 'function' ? String(value) : value;
1516
+ yield* [' ?', name];
1517
+ if (val && typeof val === 'string') {
1518
+ yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
1519
+ }
1520
+ }
1513
1521
  for (const [name, value] of Object.entries(directives)) {
1514
1522
  if (value === false || value == null) { continue; }
1515
1523
  const val = typeof value === 'function' ? String(value) : value;
@@ -1631,27 +1639,29 @@ function toString(value, formable) {
1631
1639
  /**
1632
1640
  * @typedef {object} Directives
1633
1641
  *
1634
- * @property {boolean} [fragment]
1642
+ * @property {string} [template]
1643
+ *
1644
+ * @property {boolean | string} [fragment]
1635
1645
  *
1636
- * @property {string | Function} [if]
1646
+ * @property {string | Calc} [if]
1637
1647
  * @property {boolean} [else]
1638
1648
  *
1639
1649
  * @property {string} [value] 值关联(关联为列表)
1640
- * @property {boolean | string | Function} [enum] 列表属性枚举
1650
+ * @property {boolean | string | Calc} [enum] 列表属性枚举
1641
1651
  *
1642
- * @property {string} [bind]
1643
- * @property {string | Function} [text]
1644
- * @property {string | Function} [html]
1652
+ * @property {boolean | string} [bind]
1653
+ * @property {string | Calc} [text]
1654
+ * @property {string | Calc} [html]
1645
1655
  *
1646
- * @property {string | Function} [comment] 注释
1656
+ * @property {string} [comment] 注释
1647
1657
  */
1648
1658
 
1649
1659
 
1650
1660
 
1651
1661
  /**
1652
1662
  * @typedef {object} Options
1653
- * @property {(t: string) => (vars: Record<string, any>) => any} [options.creteCalc]
1654
- * @property {(t: string) => ($event: any, vars: Record<string, any>) => any} [options.creteEvent]
1663
+ * @property {(t: string) => Calc} [options.createCalc]
1664
+ * @property {(t: string) => EventListener} [options.createEvent]
1655
1665
  * @property {Set<string>} [options.simpleTag]
1656
1666
  */
1657
1667
  /**
@@ -1659,16 +1669,31 @@ function toString(value, formable) {
1659
1669
  * @property {string} name
1660
1670
  * @property {string?} [is]
1661
1671
  * @property {string} [id]
1662
- * @property {Record<string, string | {name: string} | ((global: any) => void)>} attrs
1663
- * @property {Record<string, string | boolean | ((global: any) => void)>} classes
1664
- * @property {Record<string, string | ((global: any) => void)>} styles
1665
- * @property {Record<string, string | (($event: any, global: any) => void)>} events
1666
- * @property {Record<string, string | ((global: any) => void)>} vars
1667
- * @property {Record<string, string | Function>} aliases
1672
+ * @property {Record<string, string | {name: string} | Calc>} attrs
1673
+ * @property {Record<string, string | Calc>} params
1674
+ * @property {Record<string, string | boolean | Calc>} classes
1675
+ * @property {Record<string, string | Calc>} styles
1676
+ * @property {Record<string, string | EventListener>} events
1677
+ * @property {Record<string, string | Calc>} vars
1678
+ * @property {Record<string, string | Calc>} aliases
1668
1679
  * @property {Directives} directives
1669
1680
  * @property {(Node | string)[]} children
1670
1681
  */
1671
1682
 
1683
+ /**
1684
+ * @callback Calc
1685
+ * @param {Record<string, any>} env
1686
+ * @returns {any}
1687
+ */
1688
+
1689
+
1690
+ /**
1691
+ * @callback EventListener
1692
+ * @param {*} $event
1693
+ * @param {Record<string, any>} env
1694
+ * @returns {void}
1695
+ */
1696
+
1672
1697
  var index$1 = /*#__PURE__*/Object.freeze({
1673
1698
  __proto__: null,
1674
1699
  parse: parse,
@@ -1740,9 +1765,8 @@ const bindable = {
1740
1765
  /** @type {Set<keyof typeof bindable>} */
1741
1766
  // @ts-ignore
1742
1767
  const bindableSet = new Set(Object.keys(bindable));
1743
- /** @typedef {{get(): any; set?(v: any): void; exec?: null; store?: Store; calc?: null; }} ValueDefine */
1744
- /** @typedef {{get?: null; exec(...p: any[]): any; calc?: null}} ExecDefine */
1745
- /** @typedef {{get?: null; calc(...p: any[]): any; exec?: null;}} CalcDefine */
1768
+
1769
+ /** @import { ValueDefine, ExecDefine, CalcDefine } from './index.mjs' */
1746
1770
  /**
1747
1771
  *
1748
1772
  * @param {Store} val
@@ -1753,6 +1777,8 @@ function *toItem(val, key = '', sign = '$') {
1753
1777
  yield [`${key}`, {get: () => val.value, set: v => val.value = v, store: val}];
1754
1778
  yield [`${key}${sign}value`, {get: () => val.value, set: v => val.value = v}];
1755
1779
  yield [`${key}${sign}state`, {get: () => val.state, set: v => val.state = v}];
1780
+ yield [`${key}${sign}store`, {get: () => val}];
1781
+ yield [`${key}${sign}schema`, {get: () => val.schema}];
1756
1782
  yield [`${key}${sign}null`, {get: () => val.null}];
1757
1783
  yield [`${key}${sign}index`, {get: () => val.index}];
1758
1784
  yield [`${key}${sign}no`, {get: () => val.no}];
@@ -1760,7 +1786,6 @@ function *toItem(val, key = '', sign = '$') {
1760
1786
  yield [`${key}${sign}creatable`, {get: () => val.creatable}];
1761
1787
  yield [`${key}${sign}immutable`, {get: () => val.immutable}];
1762
1788
 
1763
- yield [`${key}${sign}schema`, {get: () => val.schema}];
1764
1789
 
1765
1790
  for (const k of bindableSet) {
1766
1791
  yield [`${key}${sign}${k}`, {get: () => val[k]}];
@@ -1772,6 +1797,9 @@ function *toItem(val, key = '', sign = '$') {
1772
1797
  yield [`${key}${sign}move`, {exec: (from, to) => val.move(from, to)}];
1773
1798
  yield [`${key}${sign}exchange`, {exec: (a, b) => val.exchange(a, b)}];
1774
1799
  }
1800
+
1801
+ /** @import { ValueDefine, ExecDefine, CalcDefine } from './index.mjs' */
1802
+
1775
1803
  /**
1776
1804
  *
1777
1805
  * @param {Store?} parent
@@ -1811,9 +1839,95 @@ function *toParentItem(parent, val, key = '', sign = '$') {
1811
1839
  parent.move(s, s + 1);
1812
1840
  }}];
1813
1841
  }
1842
+
1843
+ /** @import { ValueDefine, ExecDefine, CalcDefine } from './index.mjs' */
1844
+ /**
1845
+ *
1846
+ * @param {Record<string, ValueDefine | ExecDefine | CalcDefine>} items
1847
+ * @param {Store} store
1848
+ * @param {Store} [parent]
1849
+ */
1850
+ function setStore(items, store, parent) {
1851
+ for (const [name, val] of store) {
1852
+ for (const [b, x] of toItem(val, name)) {
1853
+ items[b] = x;
1854
+ }
1855
+ for (const [b, x] of toItem(val, name, '$$')) {
1856
+ items[b] = x;
1857
+ }
1858
+ }
1859
+
1860
+ }
1861
+
1862
+ /** @import { ValueDefine, ExecDefine, CalcDefine } from './index.mjs' */
1863
+
1864
+ /**
1865
+ * @param {Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>?} [global]
1866
+ */
1867
+ function toGlobal(global) {
1868
+ /** @type {Record<string, ValueDefine | ExecDefine | CalcDefine>} */
1869
+ const items = Object.create(null);
1870
+ if (!global || typeof global !== 'object') { return items; }
1871
+ for (const [key, value] of Object.entries(global)) {
1872
+ if (!key || key.includes('$')) { continue; }
1873
+ if (!value || typeof value !== 'object') { continue; }
1874
+ if (value instanceof Store) {
1875
+ for (const [k, v] of toItem(value, key)) {
1876
+ items[k] = v;
1877
+ }
1878
+ continue;
1879
+ }
1880
+ const {get,set,exec,calc} = value;
1881
+ if (typeof get === 'function') {
1882
+ items[key] = typeof set === 'function' ? {get,set} : {get};
1883
+ continue;
1884
+ }
1885
+ if (typeof calc === 'function') {
1886
+ items[key] = {calc};
1887
+ continue;
1888
+ }
1889
+ if (typeof exec === 'function') {
1890
+ items[key] = {exec};
1891
+ continue;
1892
+ }
1893
+ }
1894
+ return items;
1895
+ }
1896
+
1897
+ /** @import Store from '../../Store/index.mjs' */
1898
+
1899
+ /**
1900
+ * @param {Store} store
1901
+ * @param {*} env
1902
+ */
1903
+ function addStore(store, env) {
1904
+ Object.defineProperty(env, '$store', {
1905
+ value: store,
1906
+ writable: false,
1907
+ configurable: true,
1908
+ enumerable: false,
1909
+ });
1910
+ Object.defineProperty(env, '$root', {
1911
+ value: store.root,
1912
+ writable: false,
1913
+ configurable: true,
1914
+ enumerable: false,
1915
+ });
1916
+ }
1917
+
1918
+ /** @import * as Layout from '../../Layout/index.mjs' */
1919
+
1920
+
1921
+ /** @typedef {{get(): any; set?(v: any): void; exec?: null; store?: Store; calc?: null; }} ValueDefine */
1922
+ /** @typedef {{get?: null; exec(...p: any[]): any; calc?: null}} ExecDefine */
1923
+ /** @typedef {{get?: null; calc(...p: any[]): any; exec?: null;}} CalcDefine */
1924
+
1925
+ /**
1926
+ * @template {Store} [T=Store]
1927
+ */
1814
1928
  class Environment {
1815
1929
  /**
1816
- * @param {string | Function} value
1930
+ * @param {string | Layout.Calc} value
1817
1931
  */
1818
1932
  exec(value) {
1819
1933
  if (typeof value === 'string') {
@@ -1826,18 +1940,18 @@ class Environment {
1826
1940
  }
1827
1941
  }
1828
1942
  /**
1829
- * @param {string | Function} value
1943
+ * @param {string | Layout.Calc} value
1830
1944
  * @param {(value: any) => void} cb
1831
1945
  */
1832
1946
  watch(value, cb) { return watch(() => this.exec(value), cb); }
1833
1947
 
1834
1948
  /**
1835
- * @param {string | Function} name
1949
+ * @param {string | Layout.Calc | boolean | null} [name]
1836
1950
  */
1837
1951
  enum(name) {
1838
- if (typeof name === 'function') {
1839
- return () => name(this.getters);
1840
- }
1952
+ if (!name) { return true; }
1953
+ if (name === true) { return this.store; }
1954
+ if (typeof name === 'function') { return () => name(this.getters); }
1841
1955
  if (typeof name !== 'string') { return null; }
1842
1956
  const item = this.#items[name];
1843
1957
  if (typeof item?.get !== 'function') { return null }
@@ -1922,8 +2036,8 @@ class Environment {
1922
2036
  }
1923
2037
 
1924
2038
  /**
1925
- * @param {string | (($event: any, global: any) => any)} event
1926
- * @returns {(($event: any, global: any) => any)?}
2039
+ * @param {string | Layout.EventListener} event
2040
+ * @returns {Layout.EventListener?}
1927
2041
  */
1928
2042
  getEvent(event) {
1929
2043
  if (typeof event === 'function') { return event }
@@ -1936,10 +2050,11 @@ class Environment {
1936
2050
 
1937
2051
  }
1938
2052
  /**
1939
- *
2053
+ * @param {T} store
1940
2054
  * @param {Environment | Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>?} [global]
1941
2055
  */
1942
- constructor(global) {
2056
+ constructor(store, global) {
2057
+ this.store = store;
1943
2058
  if (global instanceof Environment) {
1944
2059
  this.#global = global.#global;
1945
2060
  const schemaItems = this.#schemaItems;
@@ -1952,33 +2067,8 @@ class Environment {
1952
2067
  }
1953
2068
  return;
1954
2069
  }
1955
- const items = Object.create(null);
1956
- this.#global = items;
1957
- if (!global) { return }
1958
- if (typeof global !== 'object') { return; }
1959
- for (const [key, value] of Object.entries(global)) {
1960
- if (!key || key.includes('$')) { continue; }
1961
- if (!value || typeof value !== 'object') { return; }
1962
- if (value instanceof Store) {
1963
- for (const [k, v] of toItem(value, key)) {
1964
- items[k] = v;
1965
- }
1966
- continue;
1967
- }
1968
- const {get,set,exec,calc} = value;
1969
- if (typeof get === 'function') {
1970
- items[key] = typeof set === 'function' ? {get,set} : {get};
1971
- continue;
1972
- }
1973
- if (typeof calc === 'function') {
1974
- items[key] = {calc};
1975
- continue;
1976
- }
1977
- if (typeof exec === 'function') {
1978
- items[key] = {exec};
1979
- continue;
1980
- }
1981
- }
2070
+ setStore(this.#schemaItems, store);
2071
+ this.#global = toGlobal(global);
1982
2072
  }
1983
2073
  /** @type {Record<string, ValueDefine | ExecDefine | CalcDefine>} */
1984
2074
  #global
@@ -1986,8 +2076,8 @@ class Environment {
1986
2076
  #schemaItems = Object.create(null);
1987
2077
  /** @type {Record<string, ValueDefine | ExecDefine | CalcDefine>} */
1988
2078
  #explicit = Object.create(null);
1989
- /** @type {Store?} */
1990
- #store = null
2079
+ /** @readonly @type {T} */
2080
+ store
1991
2081
  /** @type {Record<string, any>?} */
1992
2082
  #object = null
1993
2083
  /** @type {Store?} */
@@ -2003,10 +2093,14 @@ class Environment {
2003
2093
  ...this.#global,
2004
2094
  ...this.#explicit,
2005
2095
  }));
2006
- const store = this.#store;
2096
+ const store = this.store;
2007
2097
  const parent = this.#parent;
2008
2098
  const object = this.#object;
2009
- if (store) {
2099
+ if (object) {
2100
+ for (const k of Object.keys(object)) {
2101
+ ais[`$${k}`] = {get: () => object[k]};
2102
+ }
2103
+ } else {
2010
2104
  for (const [key, item] of toItem(store)) {
2011
2105
  ais[key] = item;
2012
2106
  }
@@ -2014,50 +2108,114 @@ class Environment {
2014
2108
  ais[key] = item;
2015
2109
  }
2016
2110
  }
2017
- if (object) {
2018
- for (const k of Object.keys(object)) {
2019
- ais[`$${k}`] = {get: () => object[k]};
2020
- }
2021
- }
2022
2111
  this.#allItems = ais;
2023
2112
  return ais;
2024
2113
  }
2025
2114
  /**
2026
2115
  *
2027
2116
  * @param {Store} store
2028
- * @param {Store} [parent]
2117
+ * @param {Store} parent
2029
2118
  */
2030
2119
  setStore(store, parent) {
2031
- const cloned = new Environment(this);
2032
- cloned.#store = store;
2120
+ const cloned = new Environment(store, this);
2033
2121
  if (parent) { cloned.#parent = parent; }
2034
- if (store instanceof ArrayStore) { return cloned; }
2035
- const items = cloned.#schemaItems;
2036
- for (const [name, val] of store) {
2037
- for (const [b, x] of toItem(val, name)) {
2038
- items[b] = x;
2039
- }
2040
- for (const [b, x] of toItem(val, name, '$$')) {
2041
- items[b] = x;
2122
+ setStore(cloned.#schemaItems, store);
2123
+ return cloned;
2124
+ }
2125
+ /**
2126
+ *
2127
+ * @param {string?} [name]
2128
+ */
2129
+ child(name) {
2130
+ if (!name) { return this; }
2131
+ const store = this.store.child(name);
2132
+ if (!store) { return null; }
2133
+ const cloned = new Environment(store, this);
2134
+ setStore(cloned.#schemaItems, store);
2135
+ return cloned;
2136
+ }
2137
+ /**
2138
+ *
2139
+ * @param {Layout.Node} template
2140
+ * @param {Layout.Node} source
2141
+ * @param {Environment} sourceEnv
2142
+ * @param {string | null | boolean} [bind]
2143
+ */
2144
+ params({params}, {attrs}, sourceEnv, bind) {
2145
+ /** @type {Store} */
2146
+ let store = this.store;
2147
+ if (bind === true) {
2148
+ store = sourceEnv.store;
2149
+ } else if (bind) {
2150
+ const item = sourceEnv.#items[bind];
2151
+ const s = item?.get && item.store;
2152
+ if (s) { store = s; }
2153
+ }
2154
+ if (Object.keys(params).length === 0) { return this; }
2155
+ const cloned = new Environment(store, this);
2156
+ cloned.#parent = this.#parent;
2157
+ cloned.#object = this.#object;
2158
+ const explicit = cloned.#explicit;
2159
+ const items = cloned.#items;
2160
+ for (const [key, param] of Object.entries(params)) {
2161
+ const attr = key in attrs ? attrs[key] : null;
2162
+ if (typeof attr === 'string') {
2163
+ explicit[key] = items[key] = {get: () => attr};
2164
+ } else if (attr && typeof attr === 'object') {
2165
+ const item = sourceEnv.#items[attr.name];
2166
+ if (!item?.get) { continue; }
2167
+ if (!item.store) {
2168
+ explicit[key] = items[key] = item;
2169
+ continue;
2170
+ }
2171
+ for (const [k, it] of toItem(item.store, key)) {
2172
+ explicit[k] = items[k] = it;
2173
+ }
2174
+ continue;
2175
+
2176
+ } else if (typeof attr === 'function') {
2177
+ const val = new Signal.Computed(() => attr(sourceEnv.getters));
2178
+ explicit[key] = items[key] = {
2179
+ get: () => { return val.get(); },
2180
+ };
2181
+ continue;
2182
+ } else if (typeof param === 'function') {
2183
+ const getters = cloned.getters;
2184
+ cloned.#getters = null;
2185
+ const val = new Signal.Computed(() => param(getters));
2186
+ explicit[key] = items[key] = {
2187
+ get: () => { return val.get(); },
2188
+ };
2189
+ continue;
2190
+ } else {
2191
+ const item = items[param];
2192
+ if (!item?.get) { continue; }
2193
+ if (!item.store) {
2194
+ explicit[key] = items[key] = item;
2195
+ continue;
2196
+ }
2197
+ for (const [k, it] of toItem(item.store, key)) {
2198
+ explicit[k] = items[k] = it;
2199
+ }
2200
+ continue;
2042
2201
  }
2043
2202
  }
2044
2203
  return cloned;
2045
2204
  }
2046
2205
  /** @param {Record<string, any>} object */
2047
2206
  setObject(object) {
2048
- const cloned = new Environment(this);
2207
+ const cloned = new Environment(this.store, this);
2049
2208
  cloned.#object = object;
2050
2209
  return cloned;
2051
2210
  }
2052
2211
  /**
2053
2212
  *
2054
- * @param {Record<string, string | Function>} aliases
2055
- * @param {Record<string, any>} vars
2213
+ * @param {Record<string, string | Layout.Calc>} aliases
2214
+ * @param {Record<string, string | Layout.Calc>} vars
2056
2215
  */
2057
2216
  set(aliases, vars) {
2058
2217
  if (Object.keys(aliases).length + Object.keys(vars).length === 0) { return this; }
2059
- const cloned = new Environment(this);
2060
- cloned.#store = this.#store;
2218
+ const cloned = new Environment(this.store, this);
2061
2219
  cloned.#parent = this.#parent;
2062
2220
  cloned.#object = this.#object;
2063
2221
  const explicit = cloned.#explicit;
@@ -2133,6 +2291,7 @@ class Environment {
2133
2291
  });
2134
2292
  }
2135
2293
  }
2294
+ addStore(this.store, ngt);
2136
2295
  this.#all = ngt;
2137
2296
  return ngt;
2138
2297
  }
@@ -2160,6 +2319,7 @@ class Environment {
2160
2319
  });
2161
2320
  }
2162
2321
  }
2322
+ addStore(this.store, ngt);
2163
2323
  this.#settable = ngt;
2164
2324
  return ngt;
2165
2325
  }
@@ -2186,19 +2346,22 @@ class Environment {
2186
2346
  });
2187
2347
  }
2188
2348
  }
2349
+ addStore(this.store, ngt);
2189
2350
  this.#getters = ngt;
2190
2351
  return ngt;
2191
2352
  }
2192
2353
  }
2193
2354
 
2194
2355
  /** @import { Component } from '../types.mjs' */
2356
+ /** @import * as Layout from '../Layout/index.mjs' */
2357
+
2195
2358
 
2196
2359
  /**
2197
2360
  * @param {Component.Handler} handler
2198
2361
  * @param {Environment} envs
2199
- * @param {Record<string, string | {name: string} | ((...any: any) => void)>} attrs
2362
+ * @param {Record<string, string | {name: string} | Layout.Calc>} attrs
2200
2363
  * @param {Record<string, Component.Attr>} componentAttrs
2201
- * @param {string?} [bindValue]
2364
+ * @param {string | boolean | null} [bindValue]
2202
2365
  */
2203
2366
  function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
2204
2367
 
@@ -2210,7 +2373,7 @@ function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
2210
2373
  handler.set(name, attrValue);
2211
2374
  continue;
2212
2375
  }
2213
- const attrSchema = typeof attrValue === 'function' ? attrValue : attrValue.name;
2376
+ const attrSchema = typeof attrValue === 'function' ? /** @type{Layout.Calc} */(attrValue) : attrValue.name;
2214
2377
  if (attr.immutable) {
2215
2378
  handler.set(name, envs.exec(attrSchema));
2216
2379
  continue;
@@ -2219,7 +2382,7 @@ function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
2219
2382
  continue;
2220
2383
  }
2221
2384
  const bind = attr.bind;
2222
- if (!bindValue || !bind) {
2385
+ if (!bindValue || !bind || typeof bindValue === 'boolean') {
2223
2386
  handler.set(name, attr.default);
2224
2387
  continue;
2225
2388
  }
@@ -2263,12 +2426,14 @@ function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
2263
2426
  }
2264
2427
 
2265
2428
  /** @import { Component } from '../types.mjs' */
2429
+ /** @import * as Layout from '../Layout/index.mjs' */
2430
+
2266
2431
 
2267
2432
  /**
2268
2433
  * @param {Component.Handler} handler
2269
2434
  * @param {Environment} envs
2270
- * @param {Record<string, string | {name: string} | ((...any: any) => void)>} attrs
2271
- * @param {string?} [bindValue]
2435
+ * @param {Record<string, string | {name: string} | Layout.Calc>} attrs
2436
+ * @param {string | boolean | null} [bindValue]
2272
2437
  */
2273
2438
  function bindBaseAttrs(handler, envs, attrs, bindValue) {
2274
2439
  const tag = handler.tag;
@@ -2278,7 +2443,7 @@ function bindBaseAttrs(handler, envs, attrs, bindValue) {
2278
2443
  handler.set(name, attr);
2279
2444
  continue;
2280
2445
  }
2281
- const attrSchema = typeof attr === 'function' ? attr : attr.name;
2446
+ const attrSchema = typeof attr === 'function' ? /** @type{Layout.Calc} */(attr) : attr.name;
2282
2447
  if (typeof tag === 'string' && tag.toLocaleLowerCase() === 'input' && name.toLocaleLowerCase() === 'type') {
2283
2448
  const value = envs.exec(attrSchema);
2284
2449
  handler.set(name, value);
@@ -2286,7 +2451,7 @@ function bindBaseAttrs(handler, envs, attrs, bindValue) {
2286
2451
  }
2287
2452
  bk.add(envs.watch(attrSchema, val => handler.set(name, val)));
2288
2453
  }
2289
- if (bindValue) {
2454
+ if (bindValue && typeof bindValue !== 'boolean') {
2290
2455
  for (const [key, effect] of Object.entries(envs.bindAll(bindValue) || {})) {
2291
2456
  if (typeof effect !== 'function') { continue; }
2292
2457
  bk.add(effect(val => handler.set(key, val)));
@@ -2306,10 +2471,13 @@ function bindBaseAttrs(handler, envs, attrs, bindValue) {
2306
2471
  }
2307
2472
  }
2308
2473
 
2474
+ /** @import * as Layout from '../Layout/index.mjs' */
2475
+
2476
+
2309
2477
  /**
2310
2478
  * @param {Node} node
2311
2479
  * @param {Environment} envs
2312
- * @param {Record<string, string | boolean | ((...any: any) => void)>} classes
2480
+ * @param {Record<string, string | boolean | Layout.Calc>} classes
2313
2481
  */
2314
2482
  function bindClasses(node, classes, envs) {
2315
2483
  if (!(node instanceof Element)) {
@@ -2343,6 +2511,9 @@ function bindClasses(node, classes, envs) {
2343
2511
  }
2344
2512
  }
2345
2513
 
2514
+ /** @import * as Layout from '../Layout/index.mjs' */
2515
+
2516
+
2346
2517
  /** @type {Record<string, string>} */
2347
2518
  const unit = {
2348
2519
  'width': 'px',
@@ -2409,7 +2580,7 @@ function toStyle(name, value) {
2409
2580
  /**
2410
2581
  * @param {Element} node
2411
2582
  * @param {Environment} envs
2412
- * @param {Record<string, string | ((...any: any) => void)>} classes
2583
+ * @param {Record<string, string | Layout.Calc>} classes
2413
2584
  */
2414
2585
  function bindStyles(node, classes, envs) {
2415
2586
  if (!(node instanceof HTMLElement) && !(node instanceof SVGElement)) {
@@ -2481,10 +2652,11 @@ class EventEmitter {
2481
2652
  }
2482
2653
 
2483
2654
  /** @import { Component } from '../types.mjs' */
2484
- /** @import Environment from './Environment.mjs' */
2655
+ /** @import Environment from './Environment/index.mjs' */
2656
+ /** @import Store from '../Store/index.mjs' */
2485
2657
 
2486
2658
 
2487
- /** @type {Record<string, (evt: any, param: string[], global: any) => boolean | null | void>} */
2659
+ /** @type {Record<string, Component.Event.Filter>} */
2488
2660
  const eventFilters = {
2489
2661
  stop(evt) {
2490
2662
  if (evt instanceof Event) { evt.stopPropagation(); }
@@ -2648,7 +2820,7 @@ function createContext(component, env) {
2648
2820
  if (!filters) { return; }
2649
2821
  /** @type {AddEventListenerOptions} */
2650
2822
  const options = {};
2651
- /** @type {[($event: any, param: string[], env: any) => boolean | null | void, string[], boolean][]} */
2823
+ /** @type {[Component.Event.Filter, string[], boolean][]} */
2652
2824
  const filterFns = [];
2653
2825
  if (filters) for (let f = fs.shift();f;f = fs.shift()) {
2654
2826
  const paramIndex = f.indexOf(':');
@@ -2964,19 +3136,17 @@ function createTagComponent (context, name, is) {
2964
3136
  return node;
2965
3137
  }
2966
3138
 
2967
- /** @import * as Layout from '../Layout/index.mjs' */
2968
3139
  /** @import Store, { ArrayStore } from '../Store/index.mjs' */
2969
3140
 
2970
3141
  /**
2971
3142
  *
2972
- * @param {Layout.Node} layout
2973
3143
  * @param {Element} parent
2974
3144
  * @param {Node?} next
2975
3145
  * @param {ArrayStore} store
2976
3146
  * @param {Environment} env
2977
- * @param {(layout: Layout.Node, parent: Element, next: Node | null, store: Store, env: any) => () => void} renderItem
3147
+ * @param {(next: Node | null, env: any) => () => void} renderItem
2978
3148
  */
2979
- function renderArray(layout, parent, next, store, env, renderItem) {
3149
+ function renderArray(parent, next, store, env, renderItem) {
2980
3150
  const start = parent.insertBefore(document.createComment(''), next);
2981
3151
  /** @type {Map<Store, [Comment, Comment, () => void]>} */
2982
3152
  let seMap = new Map();
@@ -2999,7 +3169,7 @@ function renderArray(layout, parent, next, store, env, renderItem) {
2999
3169
  if (!old) {
3000
3170
  const ItemStart = parent.insertBefore(document.createComment(''), nextNode);
3001
3171
  const itemEnd = parent.insertBefore(document.createComment(''), nextNode);
3002
- const d = renderItem(layout, parent, itemEnd, child, env.setStore(child, store));
3172
+ const d = renderItem(itemEnd, env.setStore(child, store));
3003
3173
  seMap.set(child, [ItemStart, itemEnd, d]);
3004
3174
  continue;
3005
3175
  }
@@ -3092,17 +3262,26 @@ function renderFillDirectives(parent, next, envs, { text, html }) {
3092
3262
  * @param {Element} parent
3093
3263
  * @param {Node?} next
3094
3264
  * @param {Environment} envs
3095
- * @param {(layout: Layout.Node) => () => void} renderItem
3265
+ * @param {Record<string, [Layout.Node, Environment]>} templates
3266
+ * @param {(layout: Layout.Node, templates: Record<string, any>) => () => void} renderItem
3096
3267
  * @returns {() => void}
3097
3268
  */
3098
- function renderList(layouts, parent, next, envs, renderItem) {
3269
+ function renderList(layouts, parent, next, envs, templates, renderItem) {
3099
3270
 
3100
3271
  /** @type {Set<() => void>?} */
3101
3272
  let bkList = new Set();
3102
- /** @type {[string | Function | null, Layout.Node][]} */
3273
+ /** @type {[string | Layout.Calc | null, Layout.Node][]} */
3103
3274
  let ifList = [];
3275
+ /** @type {Record<string, [Layout.Node, Environment]>} */
3276
+ let currentTemplates = Object.create(templates);
3277
+ for (const layout of layouts) {
3278
+ if (typeof layout === 'string') { continue; }
3279
+ const name = layout.directives.template;
3280
+ if (!name) { continue; }
3281
+ currentTemplates[name] = [layout, envs];
3282
+ }
3104
3283
 
3105
- /** @param {[string | Function | null, Layout.Node][]} list */
3284
+ /** @param {[string | Layout.Calc | null, Layout.Node][]} list */
3106
3285
  function renderIf(list) {
3107
3286
  if (!list.length || !bkList) { return; }
3108
3287
  const end = parent.insertBefore(document.createComment(''), next);
@@ -3118,7 +3297,7 @@ function renderList(layouts, parent, next, envs, renderItem) {
3118
3297
  function renderIndex(index) {
3119
3298
  const layout = list[index]?.[1];
3120
3299
  if (!layout) { return; }
3121
- destroy = renderItem(layout);
3300
+ destroy = renderItem(layout, currentTemplates);
3122
3301
  }
3123
3302
  bkList.add(() => {
3124
3303
  destroy();
@@ -3145,6 +3324,11 @@ function renderList(layouts, parent, next, envs, renderItem) {
3145
3324
  bkList.add(() => node.remove());
3146
3325
  continue;
3147
3326
  }
3327
+ if (layout.directives.template) {
3328
+ renderIf(ifList);
3329
+ ifList = [];
3330
+ continue;
3331
+ }
3148
3332
  if (ifList.length && layout.directives.else) {
3149
3333
  const ifv = layout.directives.if || null;
3150
3334
  ifList.push([ifv, layout]);
@@ -3162,7 +3346,7 @@ function renderList(layouts, parent, next, envs, renderItem) {
3162
3346
  continue;
3163
3347
  }
3164
3348
  bkList.add(
3165
- renderItem(layout)
3349
+ renderItem(layout, currentTemplates)
3166
3350
  );
3167
3351
  }
3168
3352
 
@@ -3176,23 +3360,21 @@ function renderList(layouts, parent, next, envs, renderItem) {
3176
3360
  };
3177
3361
  }
3178
3362
 
3179
- /** @import * as Layout from '../Layout/index.mjs' */
3180
- /** @import Store, { ObjectStore } from '../Store/index.mjs' */
3363
+ /** @import { ObjectStore } from '../Store/index.mjs' */
3181
3364
 
3182
3365
  /**
3183
3366
  *
3184
- * @param {Layout.Node} layout
3185
3367
  * @param {Element} parent
3186
3368
  * @param {Node?} next
3187
3369
  * @param {ObjectStore} store
3188
3370
  * @param {Environment} env
3189
- * @param {(layout: Layout.Node, parent: Element, next: Node | null, store: Store, env: any) => () => void} renderItem
3371
+ * @param {(next: Node | null, env: any) => () => void} renderItem
3190
3372
  */
3191
- function renderObject(layout, parent, next, store, env, renderItem) {
3373
+ function renderObject(parent, next, store, env, renderItem) {
3192
3374
  /** @type {(() => void)[]} */
3193
3375
  const children = [];
3194
3376
  for (const [k, child] of [...store]) {
3195
- children.push(renderItem(layout, parent, next, child, env.setStore(child, store)));
3377
+ children.push(renderItem(next, env.setStore(child, store)));
3196
3378
  }
3197
3379
 
3198
3380
  return () => {
@@ -3202,20 +3384,15 @@ function renderObject(layout, parent, next, store, env, renderItem) {
3202
3384
  };
3203
3385
  }
3204
3386
 
3205
- /** @import * as Layout from '../Layout/index.mjs' */
3206
- /** @import Store from '../Store/index.mjs' */
3207
-
3208
3387
  /**
3209
3388
  *
3210
- * @param {Layout.Node} layout
3211
3389
  * @param {Element} parent
3212
3390
  * @param {Node?} next
3213
- * @param {Store} store
3214
3391
  * @param {() => any} getter
3215
3392
  * @param {Environment} env
3216
- * @param {(layout: Layout.Node, parent: Element, next: Node | null, store: Store, env: any) => () => void} renderItem
3393
+ * @param {(next: Node | null, env: any) => () => void} renderItem
3217
3394
  */
3218
- function renderEnum(layout, parent, next, store, getter, env, renderItem) {
3395
+ function renderEnum(parent, next, getter, env, renderItem) {
3219
3396
 
3220
3397
  /** @type {Signal.Computed<[value: any, index: number, kKey: any][]>} */
3221
3398
  const list = new Signal.Computed(() => {
@@ -3256,7 +3433,7 @@ function renderEnum(layout, parent, next, store, getter, env, renderItem) {
3256
3433
  const itemEnd = parent.insertBefore(document.createComment(''), nextNode);
3257
3434
  const valueState = new Signal.State(value);
3258
3435
  const indexState = new Signal.State(index);
3259
- const d = renderItem(layout, parent, itemEnd, store, env.setObject({
3436
+ const d = renderItem(itemEnd, env.setObject({
3260
3437
  get key() { return key; },
3261
3438
  get value() { return valueState.get(); },
3262
3439
  get index() { return indexState.get(); },
@@ -3297,29 +3474,25 @@ function renderEnum(layout, parent, next, store, getter, env, renderItem) {
3297
3474
  * @param {Element} parent
3298
3475
  * @param {Node?} next
3299
3476
  * @param {Environment} env
3300
- * @param {(layout: Layout.Node) => () => void} renderItem
3301
- * @returns {() => void}
3302
- */
3303
- function renderFragment(layout, parent, next, env, renderItem) {
3304
- return renderFillDirectives(parent, next, env, layout.directives) ||
3305
- renderList(layout.children || [], parent, next, env, renderItem);
3306
-
3307
- }
3308
- /**
3309
- * @param {Layout.Node} layout
3310
- * @param {Element} parent
3311
- * @param {Node?} next
3312
- * @param {Store} store
3313
- * @param {Environment} env
3477
+ * @param {Record<string, [Layout.Node, Environment]>} templates
3314
3478
  * @param {string[]} componentPath
3315
3479
  * @param {((path: string[]) => Component?)?} [getComponent]
3316
3480
  */
3317
- function renderItem(layout, parent, next, store, env, componentPath, getComponent) {
3481
+ function renderItem(layout, parent, next, env, templates, componentPath, getComponent) {
3318
3482
  env = env.set(layout.aliases, layout.vars);
3483
+ const fragment = layout.directives.fragment;
3484
+ if (fragment && typeof fragment === 'string') {
3485
+ const template = templates[fragment];
3486
+ if (!template) { return () => {}; }
3487
+ const [templateLayout, templateEnv] = template;
3488
+ const newEnv = templateEnv.params(templateLayout, layout, env, layout.directives.bind);
3489
+ return render(templateLayout, parent, next, newEnv, templates, componentPath, getComponent);
3490
+ }
3319
3491
  if (!layout.name || layout.directives.fragment) {
3320
- return renderFragment(layout, parent, next, env, l => {
3321
- return render(l, parent, next, store, env, componentPath, getComponent);
3322
- });
3492
+ return renderFillDirectives(parent, next, env, layout.directives) ||
3493
+ renderList(layout.children || [], parent, next, env, templates, (layout, templates) => {
3494
+ return render(layout, parent, next, env, templates, componentPath, getComponent);
3495
+ });
3323
3496
  }
3324
3497
  const path = [...componentPath, layout.name];
3325
3498
  const component = getComponent?.(path);
@@ -3343,20 +3516,20 @@ function renderItem(layout, parent, next, store, env, componentPath, getComponen
3343
3516
  : createTagComponent(context, component.tag, component.is)
3344
3517
  : createTagComponent(context, layout.name, layout.is);
3345
3518
  const root = Array.isArray(r) ? r[0] : r;
3346
- const slot = Array.isArray(r) && r[1] || root;
3519
+ const slot = Array.isArray(r) ? r[1] : root;
3347
3520
  parent.insertBefore(root, next);
3348
- const children =
3521
+ const children = slot ?
3349
3522
  renderFillDirectives(slot, null, env, layout.directives)
3350
- || renderList(layout.children || [], slot, null, env, l => {
3351
- return render(l, slot, null, store, env, componentPath, getComponent);
3352
- });
3523
+ || renderList(layout.children || [], slot, null, env, templates, (layout, templates) => {
3524
+ return render(layout, slot, null, env, templates, componentPath, getComponent);
3525
+ }) : () => {};
3353
3526
 
3354
3527
 
3355
3528
  bindClasses(root, layout.classes, env);
3356
3529
  bindStyles(root, layout.styles, env);
3357
3530
 
3358
3531
  handler.init();
3359
- // TODO: 创建组件
3532
+
3360
3533
  return () => {
3361
3534
  root.remove();
3362
3535
  handler.destroy();
@@ -3369,40 +3542,30 @@ function renderItem(layout, parent, next, store, env, componentPath, getComponen
3369
3542
  * @param {Layout.Node} layout
3370
3543
  * @param {Element} parent
3371
3544
  * @param {Node?} next
3372
- * @param {Store} store
3373
3545
  * @param {Environment} env
3546
+ * @param {Record<string, [Layout.Node, Environment]>} templates
3374
3547
  * @param {string[]} componentPath
3375
3548
  * @param {((path: string[]) => Component?)?} [getComponent]
3376
3549
  * @returns {() => void}
3377
3550
  */
3378
- function render(layout, parent, next, store, env, componentPath, getComponent) {
3551
+ function render(layout, parent, next, env, templates, componentPath, getComponent) {
3379
3552
  const { directives } = layout;
3380
- const { value } = directives;
3381
- if (value) {
3382
- const newStore = store.child(value);
3383
- if (!newStore) { return () => {}; }
3384
- store = newStore;
3385
- env = env.setStore(store);
3386
- }
3387
- const enumValue = directives.enum;
3388
- if (!enumValue) {
3389
- return renderItem(layout, parent, next, store, env, componentPath, getComponent);
3390
- }
3391
- const newStore = enumValue === true ? store : env.enum(enumValue);
3392
- if (newStore instanceof ArrayStore) {
3393
- return renderArray(layout, parent, next, newStore, env, (a, b, c, store, env) => {
3394
- return renderItem(a, b, c, store, env, componentPath, getComponent);
3395
- });
3553
+ const newEnv = env.child(directives.value);
3554
+ if (!newEnv) { return () => {}; }
3555
+ const list = newEnv.enum(directives.enum);
3556
+ /** @type {(next: Node | null, env: any) => () => void} */
3557
+ const r = (next, env) => renderItem(layout, parent, next, env, templates, componentPath, getComponent);
3558
+ if (list === true) {
3559
+ return r(next, newEnv);
3396
3560
  }
3397
- if (newStore instanceof ObjectStore) {
3398
- return renderObject(layout, parent, next, newStore, env, (a, b, c, store, env) => {
3399
- return renderItem(a, b, c, store, env, componentPath, getComponent);
3400
- });
3561
+ if (list instanceof ArrayStore) {
3562
+ return renderArray(parent, next, list, newEnv, r);
3401
3563
  }
3402
- if (typeof newStore === 'function') {
3403
- return renderEnum(layout, parent, next, store, newStore, env, (a, b, c, store, env) => {
3404
- return renderItem(a, b, c, store, env, componentPath, getComponent);
3405
- });
3564
+ if (list instanceof ObjectStore) {
3565
+ return renderObject(parent, next, list, newEnv, r);
3566
+ }
3567
+ if (typeof list === 'function') {
3568
+ return renderEnum(parent, next, list, newEnv, r);
3406
3569
  }
3407
3570
  return () => { };
3408
3571
  }
@@ -3435,9 +3598,10 @@ function index (store, layouts, parent, opt1, opt2) {
3435
3598
  const options = [opt1, opt2];
3436
3599
  const components = options.find(v => typeof v === 'function');
3437
3600
  const global = options.find(v => typeof v === 'object');
3438
- const env = new Environment(global).setStore(store);
3439
- return renderList(layouts, parent, null, env, l => {
3440
- return render(l, parent, null, store, env, [], components);
3601
+ const env = new Environment(store, global);
3602
+ const templates = Object.create(null);
3603
+ return renderList(layouts, parent, null, env, templates, (layout, templates) => {
3604
+ return render(layout, parent, null, env, templates, [], components);
3441
3605
  });
3442
3606
  }
3443
3607