@mittwald/flow-react-components 1.6.0-next.41 → 1.6.0-next.43

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.
Files changed (26) hide show
  1. package/dist/assets/component-index.json +1 -1
  2. package/dist/assets/doc-properties.json +1 -1
  3. package/dist/css/all-layered.css +1 -1
  4. package/dist/css/all.css +1 -1
  5. package/dist/js/packages/components/src/components/List/components/Table/Table.mjs +21 -1
  6. package/dist/js/packages/components/src/components/List/components/Table/Table.mjs.map +1 -1
  7. package/dist/js/packages/components/src/components/List/model/table/Table.mjs +11 -1
  8. package/dist/js/packages/components/src/components/List/model/table/Table.mjs.map +1 -1
  9. package/dist/js/packages/components/src/components/List/model/table/TableBody.mjs +5 -1
  10. package/dist/js/packages/components/src/components/List/model/table/TableBody.mjs.map +1 -1
  11. package/dist/js/packages/components/src/components/List/model/table/TableColumn.mjs +4 -0
  12. package/dist/js/packages/components/src/components/List/model/table/TableColumn.mjs.map +1 -1
  13. package/dist/js/packages/components/src/components/List/model/table/TableHeader.mjs +8 -1
  14. package/dist/js/packages/components/src/components/List/model/table/TableHeader.mjs.map +1 -1
  15. package/dist/js/packages/components-base/src/list/loading/ListLoaderState.mjs +10 -5
  16. package/dist/js/packages/components-base/src/list/loading/ListLoaderState.mjs.map +1 -1
  17. package/dist/js/packages/design-tokens/dist/json-runtime/all-dark.mjs +1 -1
  18. package/dist/js/packages/design-tokens/dist/json-runtime/all-dark.mjs.map +1 -1
  19. package/dist/js/packages/design-tokens/dist/json-runtime/all-light.mjs +1 -1
  20. package/dist/js/packages/design-tokens/dist/json-runtime/all-light.mjs.map +1 -1
  21. package/dist/types/_bundled/flow-components-base/list/loading/ListLoaderState.d.ts +5 -0
  22. package/dist/types/components/List/model/table/Table.d.ts +7 -0
  23. package/dist/types/components/List/model/table/TableBody.d.ts +1 -0
  24. package/dist/types/components/List/model/table/TableColumn.d.ts +1 -0
  25. package/dist/types/components/List/model/table/TableHeader.d.ts +1 -0
  26. package/package.json +10 -10
@@ -11,10 +11,13 @@ import TableColumnView from "../../../../views/TableColumnView.mjs";
11
11
  import { TableBodyLoadingView } from "./components/TableBodyLoadingView.mjs";
12
12
  import { Row } from "./components/Row.mjs";
13
13
  import clsx from "clsx";
14
+ import { useRef } from "react";
14
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
+ import { isShallowEqual } from "remeda";
15
17
  //#region src/components/List/components/Table/Table.tsx
16
18
  var Table = () => {
17
19
  const list = useList();
20
+ const lastRender = useRef(null);
18
21
  const table = list.table;
19
22
  const listIsEmpty = list.useIsEmpty();
20
23
  const isLoading = list.loader.useIsLoading();
@@ -24,6 +27,17 @@ var Table = () => {
24
27
  const onAction = useLatestOnAction(list);
25
28
  if (!table || listIsEmpty) return null;
26
29
  const tableClassName = clsx(Table_module_default.table, isLoading && !(list.infiniteScroll && isLoadingMore) && Table_module_default.isLoading, table.componentProps.className);
30
+ const inputs = [
31
+ tableClassName,
32
+ isInitiallyLoading,
33
+ isLoading,
34
+ onAction,
35
+ triggerIndex,
36
+ triggerRef,
37
+ ...list.items.entries.flatMap((item) => [item.id, item.data])
38
+ ];
39
+ const last = lastRender.current;
40
+ if (last && isShallowEqual(last.inputs, inputs) && table.rendersSameAs(last.table)) return last.element;
27
41
  const rows = list.items.entries.map((item, index) => /* @__PURE__ */ jsx(Row, {
28
42
  id: item.id,
29
43
  data: item.data,
@@ -31,7 +45,7 @@ var Table = () => {
31
45
  onAction,
32
46
  triggerRef: index === triggerIndex ? triggerRef : void 0
33
47
  }, item.id));
34
- return /* @__PURE__ */ jsxs(TableView, {
48
+ const element = /* @__PURE__ */ jsxs(TableView, {
35
49
  ...list.componentProps,
36
50
  ...table.componentProps,
37
51
  className: tableClassName,
@@ -45,6 +59,12 @@ var Table = () => {
45
59
  children: isInitiallyLoading ? /* @__PURE__ */ jsx(TableBodyLoadingView, {}) : rows
46
60
  })]
47
61
  });
62
+ lastRender.current = {
63
+ inputs,
64
+ table,
65
+ element
66
+ };
67
+ return element;
48
68
  };
49
69
  //#endregion
50
70
  export { Table };
@@ -1 +1 @@
1
- {"version":3,"file":"Table.mjs","names":["styles"],"sources":["../../../../../../../../../src/components/List/components/Table/Table.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useList } from \"@/components/List\";\nimport styles from \"./Table.module.scss\";\nimport clsx from \"clsx\";\nimport TableView from \"@/views/TableView\";\nimport TableHeaderView from \"@/views/TableHeaderView\";\nimport TableBodyView from \"@/views/TableBodyView\";\nimport TableColumnView from \"@/views/TableColumnView\";\nimport { TableBodyLoadingView } from \"@/components/List/components/Table/components/TableBodyLoadingView\";\nimport { useInfiniteScrollTrigger } from \"@/components/List/hooks/useInfiniteScrollTrigger\";\nimport { useLatestOnAction } from \"@/components/List/hooks/useLatestOnAction\";\nimport { Row } from \"@/components/List/components/Table/components/Row\";\n\nexport const Table: FC = () => {\n const list = useList();\n const table = list.table;\n const listIsEmpty = list.useIsEmpty();\n\n const isLoading = list.loader.useIsLoading();\n const isInitiallyLoading = list.loader.useIsInitiallyLoading();\n const isLoadingMore = list.loader.useIsLoadingMore();\n\n const { triggerRef, triggerIndex } = useInfiniteScrollTrigger();\n const onAction = useLatestOnAction(list);\n\n if (!table || listIsEmpty) {\n return null;\n }\n\n const tableClassName = clsx(\n styles.table,\n isLoading && !(list.infiniteScroll && isLoadingMore) && styles.isLoading,\n table.componentProps.className,\n );\n\n const rows = list.items.entries.map((item, index) => (\n <Row\n key={item.id}\n id={item.id}\n data={item.data}\n list={list}\n onAction={onAction}\n triggerRef={index === triggerIndex ? triggerRef : undefined}\n />\n ));\n\n return (\n <TableView\n {...list.componentProps}\n {...table.componentProps}\n className={tableClassName}\n aria-hidden={isInitiallyLoading}\n aria-busy={isLoading}\n >\n <TableHeaderView {...table.header.componentProps}>\n {table.header.columns.map((col, i) => (\n <TableColumnView key={i} {...col.componentProps} />\n ))}\n </TableHeaderView>\n <TableBodyView {...table.body.componentProps}>\n {isInitiallyLoading ? <TableBodyLoadingView /> : rows}\n </TableBodyView>\n </TableView>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AAaA,IAAa,cAAkB;CAC7B,MAAM,OAAO,QAAQ;CACrB,MAAM,QAAQ,KAAK;CACnB,MAAM,cAAc,KAAK,WAAW;CAEpC,MAAM,YAAY,KAAK,OAAO,aAAa;CAC3C,MAAM,qBAAqB,KAAK,OAAO,sBAAsB;CAC7D,MAAM,gBAAgB,KAAK,OAAO,iBAAiB;CAEnD,MAAM,EAAE,YAAY,iBAAiB,yBAAyB;CAC9D,MAAM,WAAW,kBAAkB,IAAI;CAEvC,IAAI,CAAC,SAAS,aACZ,OAAO;CAGT,MAAM,iBAAiB,KACrBA,qBAAO,OACP,aAAa,EAAE,KAAK,kBAAkB,kBAAkBA,qBAAO,WAC/D,MAAM,eAAe,SACvB;CAEA,MAAM,OAAO,KAAK,MAAM,QAAQ,KAAK,MAAM,UACzC,oBAAC,KAAD;EAEE,IAAI,KAAK;EACT,MAAM,KAAK;EACL;EACI;EACV,YAAY,UAAU,eAAe,aAAa,KAAA;CACnD,GANM,KAAK,EAMX,CACF;CAED,OACE,qBAAC,WAAD;EACE,GAAI,KAAK;EACT,GAAI,MAAM;EACV,WAAW;EACX,eAAa;EACb,aAAW;EALb,UAAA,CAOE,oBAAC,iBAAD;GAAiB,GAAI,MAAM,OAAO;GAC/B,UAAA,MAAM,OAAO,QAAQ,KAAK,KAAK,MAC9B,oBAAC,iBAAD,EAAyB,GAAI,IAAI,eAAiB,GAA5B,CAA4B,CACnD;EACc,CAAA,GACjB,oBAAC,eAAD;GAAe,GAAI,MAAM,KAAK;GAC3B,UAAA,qBAAqB,oBAAC,sBAAD,CAAuB,CAAA,IAAI;EACpC,CAAA,CACN;;AAEf"}
1
+ {"version":3,"file":"Table.mjs","names":["styles"],"sources":["../../../../../../../../../src/components/List/components/Table/Table.tsx"],"sourcesContent":["import type { FC, ReactElement } from \"react\";\nimport { useRef } from \"react\";\nimport { isShallowEqual } from \"remeda\";\nimport { useList } from \"@/components/List\";\nimport styles from \"./Table.module.scss\";\nimport clsx from \"clsx\";\nimport TableView from \"@/views/TableView\";\nimport TableHeaderView from \"@/views/TableHeaderView\";\nimport TableBodyView from \"@/views/TableBodyView\";\nimport TableColumnView from \"@/views/TableColumnView\";\nimport { TableBodyLoadingView } from \"@/components/List/components/Table/components/TableBodyLoadingView\";\nimport { useInfiniteScrollTrigger } from \"@/components/List/hooks/useInfiniteScrollTrigger\";\nimport { useLatestOnAction } from \"@/components/List/hooks/useLatestOnAction\";\nimport { Row } from \"@/components/List/components/Table/components/Row\";\nimport type { Table as TableModel } from \"@/components/List/model/table/Table\";\n\ninterface LastRender {\n inputs: unknown[];\n table: TableModel<never>;\n element: ReactElement;\n}\n\nexport const Table: FC = () => {\n const list = useList();\n const lastRender = useRef<LastRender | null>(null);\n const table = list.table;\n const listIsEmpty = list.useIsEmpty();\n\n const isLoading = list.loader.useIsLoading();\n const isInitiallyLoading = list.loader.useIsInitiallyLoading();\n const isLoadingMore = list.loader.useIsLoadingMore();\n\n const { triggerRef, triggerIndex } = useInfiniteScrollTrigger();\n const onAction = useLatestOnAction(list);\n\n if (!table || listIsEmpty) {\n return null;\n }\n\n const tableClassName = clsx(\n styles.table,\n isLoading && !(list.infiniteScroll && isLoadingMore) && styles.isLoading,\n table.componentProps.className,\n );\n\n /*\n * react-aria re-renders every row and cell whenever its table renders, its\n * row memo or not (adobe/react-spectrum#10759). While nothing the table\n * shows has changed, it gets the element of the last render, so it does not\n * render at all.\n */\n const inputs = [\n tableClassName,\n isInitiallyLoading,\n isLoading,\n onAction,\n triggerIndex,\n triggerRef,\n ...list.items.entries.flatMap((item) => [item.id, item.data]),\n ];\n const last = lastRender.current;\n if (\n last &&\n isShallowEqual(last.inputs, inputs) &&\n table.rendersSameAs(last.table)\n ) {\n return last.element;\n }\n\n const rows = list.items.entries.map((item, index) => (\n <Row\n key={item.id}\n id={item.id}\n data={item.data}\n list={list}\n onAction={onAction}\n triggerRef={index === triggerIndex ? triggerRef : undefined}\n />\n ));\n\n const element = (\n <TableView\n {...list.componentProps}\n {...table.componentProps}\n className={tableClassName}\n aria-hidden={isInitiallyLoading}\n aria-busy={isLoading}\n >\n <TableHeaderView {...table.header.componentProps}>\n {table.header.columns.map((col, i) => (\n <TableColumnView key={i} {...col.componentProps} />\n ))}\n </TableHeaderView>\n <TableBodyView {...table.body.componentProps}>\n {isInitiallyLoading ? <TableBodyLoadingView /> : rows}\n </TableBodyView>\n </TableView>\n );\n lastRender.current = { inputs, table, element };\n return element;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAsBA,IAAa,cAAkB;CAC7B,MAAM,OAAO,QAAQ;CACrB,MAAM,aAAa,OAA0B,IAAI;CACjD,MAAM,QAAQ,KAAK;CACnB,MAAM,cAAc,KAAK,WAAW;CAEpC,MAAM,YAAY,KAAK,OAAO,aAAa;CAC3C,MAAM,qBAAqB,KAAK,OAAO,sBAAsB;CAC7D,MAAM,gBAAgB,KAAK,OAAO,iBAAiB;CAEnD,MAAM,EAAE,YAAY,iBAAiB,yBAAyB;CAC9D,MAAM,WAAW,kBAAkB,IAAI;CAEvC,IAAI,CAAC,SAAS,aACZ,OAAO;CAGT,MAAM,iBAAiB,KACrBA,qBAAO,OACP,aAAa,EAAE,KAAK,kBAAkB,kBAAkBA,qBAAO,WAC/D,MAAM,eAAe,SACvB;CAQA,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA;EACA,GAAG,KAAK,MAAM,QAAQ,SAAS,SAAS,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC;CAC9D;CACA,MAAM,OAAO,WAAW;CACxB,IACE,QACA,eAAe,KAAK,QAAQ,MAAM,KAClC,MAAM,cAAc,KAAK,KAAK,GAE9B,OAAO,KAAK;CAGd,MAAM,OAAO,KAAK,MAAM,QAAQ,KAAK,MAAM,UACzC,oBAAC,KAAD;EAEE,IAAI,KAAK;EACT,MAAM,KAAK;EACL;EACI;EACV,YAAY,UAAU,eAAe,aAAa,KAAA;CACnD,GANM,KAAK,EAMX,CACF;CAED,MAAM,UACJ,qBAAC,WAAD;EACE,GAAI,KAAK;EACT,GAAI,MAAM;EACV,WAAW;EACX,eAAa;EACb,aAAW;EALb,UAAA,CAOE,oBAAC,iBAAD;GAAiB,GAAI,MAAM,OAAO;GAC/B,UAAA,MAAM,OAAO,QAAQ,KAAK,KAAK,MAC9B,oBAAC,iBAAD,EAAyB,GAAI,IAAI,eAAiB,GAA5B,CAA4B,CACnD;EACc,CAAA,GACjB,oBAAC,eAAD;GAAe,GAAI,MAAM,KAAK;GAC3B,UAAA,qBAAqB,oBAAC,sBAAD,CAAuB,CAAA,IAAI;EACpC,CAAA,CACN;;CAEb,WAAW,UAAU;EAAE;EAAQ;EAAO;CAAQ;CAC9C,OAAO;AACT"}
@@ -2,6 +2,7 @@
2
2
  /* */
3
3
  import { TableHeader } from "./TableHeader.mjs";
4
4
  import { TableBody } from "./TableBody.mjs";
5
+ import { isShallowEqual } from "remeda";
5
6
  //#region src/components/List/model/table/Table.ts
6
7
  var Table = class {
7
8
  list;
@@ -9,12 +10,21 @@ var Table = class {
9
10
  body;
10
11
  componentProps;
11
12
  constructor(list, shape = {}) {
12
- const { header, body, ...restProps } = shape;
13
+ const { header, body, children: ignoredChildren, ...restProps } = shape;
13
14
  this.list = list;
14
15
  this.header = new TableHeader(this, header);
15
16
  this.body = new TableBody(this, body);
16
17
  this.componentProps = restProps;
17
18
  }
19
+ /**
20
+ * Whether `other` would render the table identically, rows aside. Like
21
+ * `TableRow.rendersSameAs`, it only holds for rows that declare
22
+ * `renderDependencies`. Props count by identity, one by one, including the
23
+ * list's own.
24
+ */
25
+ rendersSameAs(other) {
26
+ return !!other && isShallowEqual(this.list.componentProps, other.list.componentProps) && isShallowEqual(this.componentProps, other.componentProps) && this.header.rendersSameAs(other.header) && this.body.rendersSameAs(other.body);
27
+ }
18
28
  };
19
29
  //#endregion
20
30
  export { Table };
@@ -1 +1 @@
1
- {"version":3,"file":"Table.mjs","names":[],"sources":["../../../../../../../../../src/components/List/model/table/Table.ts"],"sourcesContent":["import type {\n TableShape,\n TableSupportedComponentProps,\n} from \"@/components/List/model/table/types\";\nimport type List from \"@/components/List/model/List\";\nimport { TableHeader } from \"@/components/List/model/table/TableHeader\";\nimport { TableBody } from \"@/components/List/model/table/TableBody\";\n\nexport class Table<T> {\n public readonly list: List<T>;\n public readonly header: TableHeader<T>;\n public readonly body: TableBody<T>;\n public readonly componentProps: TableSupportedComponentProps;\n\n public constructor(list: List<T>, shape: TableShape<T> = {}) {\n const { header, body, ...restProps } = shape;\n this.list = list;\n this.header = new TableHeader(this, header);\n this.body = new TableBody(this, body);\n this.componentProps = restProps;\n }\n}\n"],"mappings":";;;;;AAQA,IAAa,QAAb,MAAsB;CACpB;CACA;CACA;CACA;CAEA,YAAmB,MAAe,QAAuB,CAAC,GAAG;EAC3D,MAAM,EAAE,QAAQ,MAAM,GAAG,cAAc;EACvC,KAAK,OAAO;EACZ,KAAK,SAAS,IAAI,YAAY,MAAM,MAAM;EAC1C,KAAK,OAAO,IAAI,UAAU,MAAM,IAAI;EACpC,KAAK,iBAAiB;CACxB;AACF"}
1
+ {"version":3,"file":"Table.mjs","names":[],"sources":["../../../../../../../../../src/components/List/model/table/Table.ts"],"sourcesContent":["import type {\n TableShape,\n TableSupportedComponentProps,\n} from \"@/components/List/model/table/types\";\nimport type List from \"@/components/List/model/List\";\nimport { TableHeader } from \"@/components/List/model/table/TableHeader\";\nimport { TableBody } from \"@/components/List/model/table/TableBody\";\nimport { isShallowEqual } from \"remeda\";\n\nexport class Table<T> {\n public readonly list: List<T>;\n public readonly header: TableHeader<T>;\n public readonly body: TableBody<T>;\n public readonly componentProps: TableSupportedComponentProps;\n\n public constructor(list: List<T>, shape: TableShape<T> = {}) {\n // `children` holds the header and body elements, which arrive as `header`\n // and `body`.\n const { header, body, children: ignoredChildren, ...restProps } = shape;\n this.list = list;\n this.header = new TableHeader(this, header);\n this.body = new TableBody(this, body);\n this.componentProps = restProps;\n }\n\n /**\n * Whether `other` would render the table identically, rows aside. Like\n * `TableRow.rendersSameAs`, it only holds for rows that declare\n * `renderDependencies`. Props count by identity, one by one, including the\n * list's own.\n */\n public rendersSameAs(other?: Table<T>): boolean {\n return (\n !!other &&\n isShallowEqual(this.list.componentProps, other.list.componentProps) &&\n isShallowEqual(this.componentProps, other.componentProps) &&\n this.header.rendersSameAs(other.header) &&\n this.body.rendersSameAs(other.body)\n );\n }\n}\n"],"mappings":";;;;;;AASA,IAAa,QAAb,MAAsB;CACpB;CACA;CACA;CACA;CAEA,YAAmB,MAAe,QAAuB,CAAC,GAAG;EAG3D,MAAM,EAAE,QAAQ,MAAM,UAAU,iBAAiB,GAAG,cAAc;EAClE,KAAK,OAAO;EACZ,KAAK,SAAS,IAAI,YAAY,MAAM,MAAM;EAC1C,KAAK,OAAO,IAAI,UAAU,MAAM,IAAI;EACpC,KAAK,iBAAiB;CACxB;;;;;;;CAQA,cAAqB,OAA2B;EAC9C,OACE,CAAC,CAAC,SACF,eAAe,KAAK,KAAK,gBAAgB,MAAM,KAAK,cAAc,KAClE,eAAe,KAAK,gBAAgB,MAAM,cAAc,KACxD,KAAK,OAAO,cAAc,MAAM,MAAM,KACtC,KAAK,KAAK,cAAc,MAAM,IAAI;CAEtC;AACF"}
@@ -1,17 +1,21 @@
1
1
  "use client"
2
2
  /* */
3
3
  import { TableRow } from "./TableRow.mjs";
4
+ import { isShallowEqual } from "remeda";
4
5
  //#region src/components/List/model/table/TableBody.ts
5
6
  var TableBody = class {
6
7
  table;
7
8
  componentProps;
8
9
  row;
9
10
  constructor(table, shape = {}) {
10
- const { row, ...rest } = shape;
11
+ const { row, children: ignoredChildren, ...rest } = shape;
11
12
  this.table = table;
12
13
  this.row = new TableRow(this, row);
13
14
  this.componentProps = rest;
14
15
  }
16
+ rendersSameAs(other) {
17
+ return isShallowEqual(this.componentProps, other.componentProps) && this.row.rendersSameAs(other.row);
18
+ }
15
19
  };
16
20
  //#endregion
17
21
  export { TableBody };
@@ -1 +1 @@
1
- {"version":3,"file":"TableBody.mjs","names":[],"sources":["../../../../../../../../../src/components/List/model/table/TableBody.ts"],"sourcesContent":["import type { Table } from \"@/components/List/model/table/Table\";\nimport type {\n TableBodyShape,\n TableBodySupportedComponentProps,\n} from \"@/components/List/model/table/types\";\nimport { TableRow } from \"@/components/List/model/table/TableRow\";\n\nexport class TableBody<T> {\n public readonly table: Table<T>;\n public readonly componentProps: TableBodySupportedComponentProps;\n public readonly row: TableRow<T>;\n\n public constructor(table: Table<T>, shape: TableBodyShape<T> = {}) {\n const { row, ...rest } = shape;\n this.table = table;\n this.row = new TableRow(this, row);\n this.componentProps = rest;\n }\n}\n"],"mappings":";;;;AAOA,IAAa,YAAb,MAA0B;CACxB;CACA;CACA;CAEA,YAAmB,OAAiB,QAA2B,CAAC,GAAG;EACjE,MAAM,EAAE,KAAK,GAAG,SAAS;EACzB,KAAK,QAAQ;EACb,KAAK,MAAM,IAAI,SAAS,MAAM,GAAG;EACjC,KAAK,iBAAiB;CACxB;AACF"}
1
+ {"version":3,"file":"TableBody.mjs","names":[],"sources":["../../../../../../../../../src/components/List/model/table/TableBody.ts"],"sourcesContent":["import type { Table } from \"@/components/List/model/table/Table\";\nimport type {\n TableBodyShape,\n TableBodySupportedComponentProps,\n} from \"@/components/List/model/table/types\";\nimport { TableRow } from \"@/components/List/model/table/TableRow\";\nimport { isShallowEqual } from \"remeda\";\n\nexport class TableBody<T> {\n public readonly table: Table<T>;\n public readonly componentProps: TableBodySupportedComponentProps;\n public readonly row: TableRow<T>;\n\n public constructor(table: Table<T>, shape: TableBodyShape<T> = {}) {\n // `children` holds the row element, which arrives as `row`.\n const { row, children: ignoredChildren, ...rest } = shape;\n this.table = table;\n this.row = new TableRow(this, row);\n this.componentProps = rest;\n }\n\n public rendersSameAs(other: TableBody<T>): boolean {\n return (\n isShallowEqual(this.componentProps, other.componentProps) &&\n this.row.rendersSameAs(other.row)\n );\n }\n}\n"],"mappings":";;;;;AAQA,IAAa,YAAb,MAA0B;CACxB;CACA;CACA;CAEA,YAAmB,OAAiB,QAA2B,CAAC,GAAG;EAEjE,MAAM,EAAE,KAAK,UAAU,iBAAiB,GAAG,SAAS;EACpD,KAAK,QAAQ;EACb,KAAK,MAAM,IAAI,SAAS,MAAM,GAAG;EACjC,KAAK,iBAAiB;CACxB;CAEA,cAAqB,OAA8B;EACjD,OACE,eAAe,KAAK,gBAAgB,MAAM,cAAc,KACxD,KAAK,IAAI,cAAc,MAAM,GAAG;CAEpC;AACF"}
@@ -1,5 +1,6 @@
1
1
  "use client"
2
2
  /* */
3
+ import { isShallowEqual } from "remeda";
3
4
  //#region src/components/List/model/table/TableColumn.ts
4
5
  var TableColumn = class {
5
6
  tableHeader;
@@ -8,6 +9,9 @@ var TableColumn = class {
8
9
  this.tableHeader = tableHeader;
9
10
  this.componentProps = shape;
10
11
  }
12
+ rendersSameAs(other) {
13
+ return isShallowEqual(this.componentProps, other.componentProps);
14
+ }
11
15
  };
12
16
  //#endregion
13
17
  export { TableColumn };
@@ -1 +1 @@
1
- {"version":3,"file":"TableColumn.mjs","names":[],"sources":["../../../../../../../../../src/components/List/model/table/TableColumn.ts"],"sourcesContent":["import type {\n TableColumnShape,\n TableColumnSupportedComponentProps,\n} from \"@/components/List/model/table/types\";\nimport type { TableHeader } from \"@/components/List/model/table/TableHeader\";\n\nexport class TableColumn<T> {\n public readonly tableHeader: TableHeader<T>;\n public readonly componentProps: TableColumnSupportedComponentProps;\n\n public constructor(\n tableHeader: TableHeader<T>,\n shape: TableColumnShape = {},\n ) {\n this.tableHeader = tableHeader;\n this.componentProps = shape;\n }\n}\n"],"mappings":";;;AAMA,IAAa,cAAb,MAA4B;CAC1B;CACA;CAEA,YACE,aACA,QAA0B,CAAC,GAC3B;EACA,KAAK,cAAc;EACnB,KAAK,iBAAiB;CACxB;AACF"}
1
+ {"version":3,"file":"TableColumn.mjs","names":[],"sources":["../../../../../../../../../src/components/List/model/table/TableColumn.ts"],"sourcesContent":["import type {\n TableColumnShape,\n TableColumnSupportedComponentProps,\n} from \"@/components/List/model/table/types\";\nimport type { TableHeader } from \"@/components/List/model/table/TableHeader\";\nimport { isShallowEqual } from \"remeda\";\n\nexport class TableColumn<T> {\n public readonly tableHeader: TableHeader<T>;\n public readonly componentProps: TableColumnSupportedComponentProps;\n\n public constructor(\n tableHeader: TableHeader<T>,\n shape: TableColumnShape = {},\n ) {\n this.tableHeader = tableHeader;\n this.componentProps = shape;\n }\n\n public rendersSameAs(other: TableColumn<T>): boolean {\n return isShallowEqual(this.componentProps, other.componentProps);\n }\n}\n"],"mappings":";;;;AAOA,IAAa,cAAb,MAA4B;CAC1B;CACA;CAEA,YACE,aACA,QAA0B,CAAC,GAC3B;EACA,KAAK,cAAc;EACnB,KAAK,iBAAiB;CACxB;CAEA,cAAqB,OAAgC;EACnD,OAAO,eAAe,KAAK,gBAAgB,MAAM,cAAc;CACjE;AACF"}
@@ -1,17 +1,24 @@
1
1
  "use client"
2
2
  /* */
3
3
  import { TableColumn } from "./TableColumn.mjs";
4
+ import { isShallowEqual } from "remeda";
4
5
  //#region src/components/List/model/table/TableHeader.ts
5
6
  var TableHeader = class {
6
7
  table;
7
8
  componentProps;
8
9
  columns;
9
10
  constructor(table, shape = {}) {
10
- const { columns = [], ...rest } = shape;
11
+ const { columns = [], children: ignoredChildren, ...rest } = shape;
11
12
  this.table = table;
12
13
  this.columns = columns.map((colShape) => new TableColumn(this, colShape));
13
14
  this.componentProps = rest;
14
15
  }
16
+ rendersSameAs(other) {
17
+ return isShallowEqual(this.componentProps, other.componentProps) && this.columns.length === other.columns.length && this.columns.every((column, index) => {
18
+ const otherColumn = other.columns[index];
19
+ return !!otherColumn && column.rendersSameAs(otherColumn);
20
+ });
21
+ }
15
22
  };
16
23
  //#endregion
17
24
  export { TableHeader };
@@ -1 +1 @@
1
- {"version":3,"file":"TableHeader.mjs","names":[],"sources":["../../../../../../../../../src/components/List/model/table/TableHeader.ts"],"sourcesContent":["import type { Table } from \"@/components/List/model/table/Table\";\nimport type {\n TableHeaderShape,\n TableHeaderSupportedComponentProps,\n} from \"@/components/List/model/table/types\";\nimport { TableColumn } from \"@/components/List/model/table/TableColumn\";\n\nexport class TableHeader<T> {\n public readonly table: Table<T>;\n public readonly componentProps: TableHeaderSupportedComponentProps;\n public readonly columns: TableColumn<T>[];\n\n public constructor(table: Table<T>, shape: TableHeaderShape = {}) {\n const { columns = [], ...rest } = shape;\n this.table = table;\n this.columns = columns.map((colShape) => new TableColumn(this, colShape));\n this.componentProps = rest;\n }\n}\n"],"mappings":";;;;AAOA,IAAa,cAAb,MAA4B;CAC1B;CACA;CACA;CAEA,YAAmB,OAAiB,QAA0B,CAAC,GAAG;EAChE,MAAM,EAAE,UAAU,CAAC,GAAG,GAAG,SAAS;EAClC,KAAK,QAAQ;EACb,KAAK,UAAU,QAAQ,KAAK,aAAa,IAAI,YAAY,MAAM,QAAQ,CAAC;EACxE,KAAK,iBAAiB;CACxB;AACF"}
1
+ {"version":3,"file":"TableHeader.mjs","names":[],"sources":["../../../../../../../../../src/components/List/model/table/TableHeader.ts"],"sourcesContent":["import type { Table } from \"@/components/List/model/table/Table\";\nimport type {\n TableHeaderShape,\n TableHeaderSupportedComponentProps,\n} from \"@/components/List/model/table/types\";\nimport { TableColumn } from \"@/components/List/model/table/TableColumn\";\nimport { isShallowEqual } from \"remeda\";\n\nexport class TableHeader<T> {\n public readonly table: Table<T>;\n public readonly componentProps: TableHeaderSupportedComponentProps;\n public readonly columns: TableColumn<T>[];\n\n public constructor(table: Table<T>, shape: TableHeaderShape = {}) {\n // `children` holds the column elements, which arrive as `columns`.\n const { columns = [], children: ignoredChildren, ...rest } = shape;\n this.table = table;\n this.columns = columns.map((colShape) => new TableColumn(this, colShape));\n this.componentProps = rest;\n }\n\n public rendersSameAs(other: TableHeader<T>): boolean {\n return (\n isShallowEqual(this.componentProps, other.componentProps) &&\n this.columns.length === other.columns.length &&\n this.columns.every((column, index) => {\n const otherColumn = other.columns[index];\n return !!otherColumn && column.rendersSameAs(otherColumn);\n })\n );\n }\n}\n"],"mappings":";;;;;AAQA,IAAa,cAAb,MAA4B;CAC1B;CACA;CACA;CAEA,YAAmB,OAAiB,QAA0B,CAAC,GAAG;EAEhE,MAAM,EAAE,UAAU,CAAC,GAAG,UAAU,iBAAiB,GAAG,SAAS;EAC7D,KAAK,QAAQ;EACb,KAAK,UAAU,QAAQ,KAAK,aAAa,IAAI,YAAY,MAAM,QAAQ,CAAC;EACxE,KAAK,iBAAiB;CACxB;CAEA,cAAqB,OAAgC;EACnD,OACE,eAAe,KAAK,gBAAgB,MAAM,cAAc,KACxD,KAAK,QAAQ,WAAW,MAAM,QAAQ,UACtC,KAAK,QAAQ,OAAO,QAAQ,UAAU;GACpC,MAAM,cAAc,MAAM,QAAQ;GAClC,OAAO,CAAC,CAAC,eAAe,OAAO,cAAc,WAAW;EAC1D,CAAC;CAEL;AACF"}
@@ -1,6 +1,6 @@
1
1
  "use client"
2
2
  /* */
3
- import { uniqueBy } from "remeda";
3
+ import { isShallowEqual, uniqueBy } from "remeda";
4
4
  import { action, computed, makeObservable, observable } from "mobx";
5
5
  //#region ../components-base/src/list/loading/ListLoaderState.ts
6
6
  /**
@@ -49,12 +49,17 @@ var ListLoaderState = class {
49
49
  this.batchLoadingStates = [];
50
50
  this.dataBatches = [];
51
51
  }
52
+ /**
53
+ * Keeps the current batch when `data` holds the same items in the same order.
54
+ * A loader that builds a new array on every fetch — a refetch whose items its
55
+ * data layer reuses — would otherwise re-render the whole list for nothing.
56
+ */
52
57
  setDataBatch(index, data) {
53
58
  if (this.dataBatches.length === 0) this.prevDataBatches = [];
54
- if (this.dataBatches[index] !== data) {
55
- this.dataBatches[index] = data;
56
- this.prevDataBatches[index] = data;
57
- }
59
+ const current = this.dataBatches[index];
60
+ if (current !== void 0 && isShallowEqual(current, data)) return;
61
+ this.dataBatches[index] = data;
62
+ this.prevDataBatches[index] = data;
58
63
  }
59
64
  setBatchLoadingState(index, state) {
60
65
  if (state === "error" || state === "loaded") this.setIsInitiallyLoading(false);
@@ -1 +1 @@
1
- {"version":3,"file":"ListLoaderState.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/loading/ListLoaderState.ts"],"sourcesContent":["import type { BatchLoadingState, ListData } from \"./types\";\nimport { action, computed, makeObservable, observable } from \"mobx\";\nimport { uniqueBy } from \"remeda\";\n\nexport interface ListLoaderStateOptions<T> {\n /**\n * Identifies an item, so the same one loaded in two batches appears once.\n * Without it the batches are concatenated as they arrive.\n */\n getItemId?: (item: T) => string;\n}\n\n/**\n * What a list has loaded so far, and how far each batch has got.\n *\n * MobX, and nothing else — no hook, no framework. A binding reads it through\n * its own reactivity: React with `useSelector`, Vue with `watchMobxValue`. That\n * split is the point: the batching, the deduplication and the \"still loading\"\n * rules are one implementation, and only the subscription is written twice.\n *\n * What is _not_ here is the loading itself. Fetching a batch is\n * `usePromise`/Suspense in React and something else in Vue, so it stays with\n * the binding, and only its outcome is reported here.\n */\nexport class ListLoaderState<T> {\n public dataBatches: ListData<T>[] = [];\n public batchLoadingStates: BatchLoadingState[] = [\"void\"];\n public metadata?: unknown = undefined;\n public isInitiallyLoading = true;\n\n /**\n * The last non-empty result, kept outside MobX on purpose: it exists so a\n * reset can keep rendering the previous data instead of flashing empty, and\n * observing it would make that very reset re-render.\n */\n public prevDataBatches: ListData<T>[] = [];\n\n private readonly getItemId?: (item: T) => string;\n\n public constructor(options: ListLoaderStateOptions<T> = {}) {\n this.getItemId = options.getItemId;\n\n makeObservable(this, {\n prevDataBatches: false,\n dataBatches: observable.shallow,\n batchLoadingStates: observable.shallow,\n metadata: observable,\n mergedData: computed,\n isLoading: computed,\n isLoadingMore: computed,\n isInitiallyLoading: observable,\n setIsInitiallyLoading: action.bound,\n reset: action.bound,\n setDataBatch: action.bound,\n setBatchLoadingState: action.bound,\n setMetadata: action.bound,\n });\n }\n\n public reset(): void {\n this.batchLoadingStates = [];\n this.dataBatches = [];\n }\n\n public setDataBatch(index: number, data: ListData<T>): void {\n if (this.dataBatches.length === 0) {\n this.prevDataBatches = [];\n }\n\n if (this.dataBatches[index] !== data) {\n this.dataBatches[index] = data;\n this.prevDataBatches[index] = data;\n }\n }\n\n public setBatchLoadingState(index: number, state: BatchLoadingState): void {\n if (state === \"error\" || state === \"loaded\") {\n this.setIsInitiallyLoading(false);\n }\n if (this.batchLoadingStates[index] !== state) {\n this.batchLoadingStates[index] = state;\n }\n }\n\n public setMetadata(metadata?: unknown): void {\n this.metadata = metadata;\n }\n\n public setIsInitiallyLoading(isInitiallyLoading: boolean): void {\n this.isInitiallyLoading = isInitiallyLoading;\n }\n\n public get mergedData(): T[] {\n const dataBatches =\n this.dataBatches.length === 0 ? this.prevDataBatches : this.dataBatches;\n\n const merged = dataBatches.flatMap((d) => d);\n return this.getItemId ? uniqueBy(merged, this.getItemId) : merged;\n }\n\n public get isLoading(): boolean {\n return this.batchLoadingStates.some((s) => s === \"loading\" || s === \"void\");\n }\n\n public get isLoadingMore(): boolean {\n return this.isLoading && this.dataBatches.length > 0;\n }\n\n public isBatchLoaded(batchIndex: number): boolean {\n return batchIndex in this.dataBatches;\n }\n}\n\nexport default ListLoaderState;\n"],"mappings":";;;;;;;;;;;;;;;;;AAwBA,IAAa,kBAAb,MAAgC;CAC9B,cAAoC,CAAC;CACrC,qBAAiD,CAAC,MAAM;CACxD,WAA4B,KAAA;CAC5B,qBAA4B;;;;;;CAO5B,kBAAwC,CAAC;CAEzC;CAEA,YAAmB,UAAqC,CAAC,GAAG;EAC1D,KAAK,YAAY,QAAQ;EAEzB,eAAe,MAAM;GACnB,iBAAiB;GACjB,aAAa,WAAW;GACxB,oBAAoB,WAAW;GAC/B,UAAU;GACV,YAAY;GACZ,WAAW;GACX,eAAe;GACf,oBAAoB;GACpB,uBAAuB,OAAO;GAC9B,OAAO,OAAO;GACd,cAAc,OAAO;GACrB,sBAAsB,OAAO;GAC7B,aAAa,OAAO;EACtB,CAAC;CACH;CAEA,QAAqB;EACnB,KAAK,qBAAqB,CAAC;EAC3B,KAAK,cAAc,CAAC;CACtB;CAEA,aAAoB,OAAe,MAAyB;EAC1D,IAAI,KAAK,YAAY,WAAW,GAC9B,KAAK,kBAAkB,CAAC;EAG1B,IAAI,KAAK,YAAY,WAAW,MAAM;GACpC,KAAK,YAAY,SAAS;GAC1B,KAAK,gBAAgB,SAAS;EAChC;CACF;CAEA,qBAA4B,OAAe,OAAgC;EACzE,IAAI,UAAU,WAAW,UAAU,UACjC,KAAK,sBAAsB,KAAK;EAElC,IAAI,KAAK,mBAAmB,WAAW,OACrC,KAAK,mBAAmB,SAAS;CAErC;CAEA,YAAmB,UAA0B;EAC3C,KAAK,WAAW;CAClB;CAEA,sBAA6B,oBAAmC;EAC9D,KAAK,qBAAqB;CAC5B;CAEA,IAAW,aAAkB;EAI3B,MAAM,UAFJ,KAAK,YAAY,WAAW,IAAI,KAAK,kBAAkB,KAAK,YAAA,CAEnC,SAAS,MAAM,CAAC;EAC3C,OAAO,KAAK,YAAY,SAAS,QAAQ,KAAK,SAAS,IAAI;CAC7D;CAEA,IAAW,YAAqB;EAC9B,OAAO,KAAK,mBAAmB,MAAM,MAAM,MAAM,aAAa,MAAM,MAAM;CAC5E;CAEA,IAAW,gBAAyB;EAClC,OAAO,KAAK,aAAa,KAAK,YAAY,SAAS;CACrD;CAEA,cAAqB,YAA6B;EAChD,OAAO,cAAc,KAAK;CAC5B;AACF"}
1
+ {"version":3,"file":"ListLoaderState.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/loading/ListLoaderState.ts"],"sourcesContent":["import type { BatchLoadingState, ListData } from \"./types\";\nimport { action, computed, makeObservable, observable } from \"mobx\";\nimport { isShallowEqual, uniqueBy } from \"remeda\";\n\nexport interface ListLoaderStateOptions<T> {\n /**\n * Identifies an item, so the same one loaded in two batches appears once.\n * Without it the batches are concatenated as they arrive.\n */\n getItemId?: (item: T) => string;\n}\n\n/**\n * What a list has loaded so far, and how far each batch has got.\n *\n * MobX, and nothing else — no hook, no framework. A binding reads it through\n * its own reactivity: React with `useSelector`, Vue with `watchMobxValue`. That\n * split is the point: the batching, the deduplication and the \"still loading\"\n * rules are one implementation, and only the subscription is written twice.\n *\n * What is _not_ here is the loading itself. Fetching a batch is\n * `usePromise`/Suspense in React and something else in Vue, so it stays with\n * the binding, and only its outcome is reported here.\n */\nexport class ListLoaderState<T> {\n public dataBatches: ListData<T>[] = [];\n public batchLoadingStates: BatchLoadingState[] = [\"void\"];\n public metadata?: unknown = undefined;\n public isInitiallyLoading = true;\n\n /**\n * The last non-empty result, kept outside MobX on purpose: it exists so a\n * reset can keep rendering the previous data instead of flashing empty, and\n * observing it would make that very reset re-render.\n */\n public prevDataBatches: ListData<T>[] = [];\n\n private readonly getItemId?: (item: T) => string;\n\n public constructor(options: ListLoaderStateOptions<T> = {}) {\n this.getItemId = options.getItemId;\n\n makeObservable(this, {\n prevDataBatches: false,\n dataBatches: observable.shallow,\n batchLoadingStates: observable.shallow,\n metadata: observable,\n mergedData: computed,\n isLoading: computed,\n isLoadingMore: computed,\n isInitiallyLoading: observable,\n setIsInitiallyLoading: action.bound,\n reset: action.bound,\n setDataBatch: action.bound,\n setBatchLoadingState: action.bound,\n setMetadata: action.bound,\n });\n }\n\n public reset(): void {\n this.batchLoadingStates = [];\n this.dataBatches = [];\n }\n\n /**\n * Keeps the current batch when `data` holds the same items in the same order.\n * A loader that builds a new array on every fetch — a refetch whose items its\n * data layer reuses — would otherwise re-render the whole list for nothing.\n */\n public setDataBatch(index: number, data: ListData<T>): void {\n if (this.dataBatches.length === 0) {\n this.prevDataBatches = [];\n }\n\n const current = this.dataBatches[index];\n if (current !== undefined && isShallowEqual(current, data)) {\n return;\n }\n\n this.dataBatches[index] = data;\n this.prevDataBatches[index] = data;\n }\n\n public setBatchLoadingState(index: number, state: BatchLoadingState): void {\n if (state === \"error\" || state === \"loaded\") {\n this.setIsInitiallyLoading(false);\n }\n if (this.batchLoadingStates[index] !== state) {\n this.batchLoadingStates[index] = state;\n }\n }\n\n public setMetadata(metadata?: unknown): void {\n this.metadata = metadata;\n }\n\n public setIsInitiallyLoading(isInitiallyLoading: boolean): void {\n this.isInitiallyLoading = isInitiallyLoading;\n }\n\n public get mergedData(): T[] {\n const dataBatches =\n this.dataBatches.length === 0 ? this.prevDataBatches : this.dataBatches;\n\n const merged = dataBatches.flatMap((d) => d);\n return this.getItemId ? uniqueBy(merged, this.getItemId) : merged;\n }\n\n public get isLoading(): boolean {\n return this.batchLoadingStates.some((s) => s === \"loading\" || s === \"void\");\n }\n\n public get isLoadingMore(): boolean {\n return this.isLoading && this.dataBatches.length > 0;\n }\n\n public isBatchLoaded(batchIndex: number): boolean {\n return batchIndex in this.dataBatches;\n }\n}\n\nexport default ListLoaderState;\n"],"mappings":";;;;;;;;;;;;;;;;;AAwBA,IAAa,kBAAb,MAAgC;CAC9B,cAAoC,CAAC;CACrC,qBAAiD,CAAC,MAAM;CACxD,WAA4B,KAAA;CAC5B,qBAA4B;;;;;;CAO5B,kBAAwC,CAAC;CAEzC;CAEA,YAAmB,UAAqC,CAAC,GAAG;EAC1D,KAAK,YAAY,QAAQ;EAEzB,eAAe,MAAM;GACnB,iBAAiB;GACjB,aAAa,WAAW;GACxB,oBAAoB,WAAW;GAC/B,UAAU;GACV,YAAY;GACZ,WAAW;GACX,eAAe;GACf,oBAAoB;GACpB,uBAAuB,OAAO;GAC9B,OAAO,OAAO;GACd,cAAc,OAAO;GACrB,sBAAsB,OAAO;GAC7B,aAAa,OAAO;EACtB,CAAC;CACH;CAEA,QAAqB;EACnB,KAAK,qBAAqB,CAAC;EAC3B,KAAK,cAAc,CAAC;CACtB;;;;;;CAOA,aAAoB,OAAe,MAAyB;EAC1D,IAAI,KAAK,YAAY,WAAW,GAC9B,KAAK,kBAAkB,CAAC;EAG1B,MAAM,UAAU,KAAK,YAAY;EACjC,IAAI,YAAY,KAAA,KAAa,eAAe,SAAS,IAAI,GACvD;EAGF,KAAK,YAAY,SAAS;EAC1B,KAAK,gBAAgB,SAAS;CAChC;CAEA,qBAA4B,OAAe,OAAgC;EACzE,IAAI,UAAU,WAAW,UAAU,UACjC,KAAK,sBAAsB,KAAK;EAElC,IAAI,KAAK,mBAAmB,WAAW,OACrC,KAAK,mBAAmB,SAAS;CAErC;CAEA,YAAmB,UAA0B;EAC3C,KAAK,WAAW;CAClB;CAEA,sBAA6B,oBAAmC;EAC9D,KAAK,qBAAqB;CAC5B;CAEA,IAAW,aAAkB;EAI3B,MAAM,UAFJ,KAAK,YAAY,WAAW,IAAI,KAAK,kBAAkB,KAAK,YAAA,CAEnC,SAAS,MAAM,CAAC;EAC3C,OAAO,KAAK,YAAY,SAAS,QAAQ,KAAK,SAAS,IAAI;CAC7D;CAEA,IAAW,YAAqB;EAC9B,OAAO,KAAK,mBAAmB,MAAM,MAAM,MAAM,aAAa,MAAM,MAAM;CAC5E;CAEA,IAAW,gBAAyB;EAClC,OAAO,KAAK,aAAa,KAAK,YAAY,SAAS;CACrD;CAEA,cAAqB,YAA6B;EAChD,OAAO,cAAc,KAAK;CAC5B;AACF"}
@@ -2811,7 +2811,7 @@ var table = {
2811
2811
  }
2812
2812
  };
2813
2813
  var texture = { "grain": {
2814
- "value": "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0.33 0.33 0.33 0 0 0.33 0.33 0.33 0 0 0.33 0.33 0.33 0 0 0 0 0 0 1'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.8' intercept='0.1'/%3E%3CfeFuncG type='linear' slope='0.8' intercept='0.1'/%3E%3CfeFuncB type='linear' slope='0.8' intercept='0.1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")",
2814
+ "value": "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.45' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.21' intercept='0.3950'/%3E%3CfeFuncG type='linear' slope='0.21' intercept='0.3950'/%3E%3CfeFuncB type='linear' slope='0.21' intercept='0.3950'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")",
2815
2815
  "path": ["texture", "grain"]
2816
2816
  } };
2817
2817
  var all_dark_default = {