@dxos/react-ui-table 0.8.4-main.f9ba587 → 0.8.4-main.fcfe5033a5

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 (172) hide show
  1. package/dist/lib/browser/chunk-BF54SSNL.mjs +70 -0
  2. package/dist/lib/browser/chunk-BF54SSNL.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-F7Y374KL.mjs +1751 -0
  4. package/dist/lib/browser/chunk-F7Y374KL.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +1195 -2846
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +114 -0
  9. package/dist/lib/browser/testing/index.mjs.map +7 -0
  10. package/dist/lib/browser/types/index.mjs +3 -5
  11. package/dist/lib/node-esm/chunk-CCJ4LOVM.mjs +1753 -0
  12. package/dist/lib/node-esm/chunk-CCJ4LOVM.mjs.map +7 -0
  13. package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs +71 -0
  14. package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +1195 -2846
  16. package/dist/lib/node-esm/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +115 -0
  19. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  20. package/dist/lib/node-esm/types/index.mjs +3 -5
  21. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +2 -3
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +4 -2
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
  26. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +35 -3
  28. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Relations.stories.d.ts +110 -0
  30. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  31. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  32. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/Table.d.ts +21 -18
  34. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  35. package/dist/types/src/components/Table/Table.stories.d.ts +109 -6
  36. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/Table/TableContent.d.ts +17 -0
  38. package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
  39. package/dist/types/src/components/Table/TableToolbar.d.ts +21 -0
  40. package/dist/types/src/components/Table/TableToolbar.d.ts.map +1 -0
  41. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
  42. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  43. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +14 -9
  44. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  45. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +12 -18
  46. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  47. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +38 -5
  48. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  49. package/dist/types/src/components/TableCellEditor/index.d.ts +1 -0
  50. package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -1
  51. package/dist/types/src/components/index.d.ts +0 -1
  52. package/dist/types/src/components/index.d.ts.map +1 -1
  53. package/dist/types/src/components/testing.d.ts +26 -56
  54. package/dist/types/src/components/testing.d.ts.map +1 -1
  55. package/dist/types/src/hooks/index.d.ts +2 -1
  56. package/dist/types/src/hooks/index.d.ts.map +1 -1
  57. package/dist/types/src/hooks/useAddRow.d.ts +6 -6
  58. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  59. package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
  60. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
  61. package/dist/types/src/hooks/useTableModel.d.ts +11 -10
  62. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  63. package/dist/types/src/index.d.ts +0 -1
  64. package/dist/types/src/index.d.ts.map +1 -1
  65. package/dist/types/src/model/modal-controller.d.ts +5 -8
  66. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  67. package/dist/types/src/model/selection-model.d.ts +17 -7
  68. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  69. package/dist/types/src/model/table-model.d.ts +116 -34
  70. package/dist/types/src/model/table-model.d.ts.map +1 -1
  71. package/dist/types/src/model/table-presentation.d.ts +5 -2
  72. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  73. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  74. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  75. package/dist/types/src/testing/index.d.ts +2 -0
  76. package/dist/types/src/testing/index.d.ts.map +1 -0
  77. package/dist/types/src/testing/useTestTableModel.d.ts +25 -0
  78. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -0
  79. package/dist/types/src/translations.d.ts +21 -23
  80. package/dist/types/src/translations.d.ts.map +1 -1
  81. package/dist/types/src/types/Table.d.ts +26 -0
  82. package/dist/types/src/types/Table.d.ts.map +1 -0
  83. package/dist/types/src/types/index.d.ts +1 -1
  84. package/dist/types/src/types/index.d.ts.map +1 -1
  85. package/dist/types/src/util/dynamic-table.d.ts +15 -14
  86. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  87. package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
  88. package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
  89. package/dist/types/src/util/index.d.ts +2 -1
  90. package/dist/types/src/util/index.d.ts.map +1 -1
  91. package/dist/types/src/util/query-ast.d.ts +7 -0
  92. package/dist/types/src/util/query-ast.d.ts.map +1 -0
  93. package/dist/types/src/util/schema.d.ts +1 -1
  94. package/dist/types/src/util/schema.d.ts.map +1 -1
  95. package/dist/types/src/util/sort.d.ts +12 -0
  96. package/dist/types/src/util/sort.d.ts.map +1 -0
  97. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  98. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  99. package/dist/types/tsconfig.tsbuildinfo +1 -1
  100. package/package.json +70 -55
  101. package/src/components/Table/ColumnActionsMenu.tsx +16 -12
  102. package/src/components/Table/ColumnSettings.tsx +18 -15
  103. package/src/components/Table/DynamicTable.stories.tsx +38 -35
  104. package/src/components/Table/DynamicTable.tsx +38 -34
  105. package/src/components/Table/Relations.stories.tsx +245 -0
  106. package/src/components/Table/RowActionsMenu.tsx +26 -17
  107. package/src/components/Table/Table.stories.tsx +196 -218
  108. package/src/components/Table/Table.tsx +47 -376
  109. package/src/components/Table/TableContent.tsx +421 -0
  110. package/src/components/Table/TableToolbar.tsx +111 -0
  111. package/src/components/TableCellEditor/CellValidationMessage.tsx +6 -6
  112. package/src/components/TableCellEditor/FormCellEditor.tsx +152 -49
  113. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +37 -77
  114. package/src/components/TableCellEditor/TableCellEditor.tsx +104 -233
  115. package/src/components/TableCellEditor/index.ts +1 -0
  116. package/src/components/index.ts +0 -1
  117. package/src/components/testing.ts +46 -37
  118. package/src/hooks/index.ts +2 -1
  119. package/src/hooks/useAddRow.ts +14 -14
  120. package/src/hooks/useProjectionModel.ts +39 -0
  121. package/src/hooks/useTableModel.ts +41 -35
  122. package/src/index.ts +0 -1
  123. package/src/model/modal-controller.ts +24 -41
  124. package/src/model/selection-model.ts +75 -41
  125. package/src/model/table-model.test.ts +91 -56
  126. package/src/model/table-model.ts +468 -187
  127. package/src/model/table-presentation.test.ts +69 -59
  128. package/src/model/table-presentation.ts +112 -66
  129. package/src/playwright/TableManager.ts +13 -6
  130. package/src/playwright/playwright.config.ts +1 -1
  131. package/src/playwright/smoke.spec.ts +180 -43
  132. package/src/testing/index.ts +5 -0
  133. package/src/testing/useTestTableModel.ts +133 -0
  134. package/src/translations.ts +20 -22
  135. package/src/types/Table.ts +79 -0
  136. package/src/types/index.ts +2 -2
  137. package/src/util/dynamic-table.test.ts +70 -0
  138. package/src/util/dynamic-table.ts +51 -36
  139. package/src/util/index.ts +2 -1
  140. package/src/util/query-ast.ts +22 -0
  141. package/src/util/schema.ts +4 -4
  142. package/src/util/sort.ts +90 -0
  143. package/src/util/table-buttons.ts +4 -3
  144. package/src/util/table-controls.ts +6 -3
  145. package/dist/lib/browser/chunk-Q5QQXJUO.mjs +0 -27
  146. package/dist/lib/browser/chunk-Q5QQXJUO.mjs.map +0 -7
  147. package/dist/lib/node-esm/chunk-ZNOU6LHG.mjs +0 -29
  148. package/dist/lib/node-esm/chunk-ZNOU6LHG.mjs.map +0 -7
  149. package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
  150. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
  151. package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
  152. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
  153. package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
  154. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
  155. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +0 -21
  156. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +0 -1
  157. package/dist/types/src/components/TableToolbar/index.d.ts +0 -2
  158. package/dist/types/src/components/TableToolbar/index.d.ts.map +0 -1
  159. package/dist/types/src/model/table-sorting.d.ts +0 -53
  160. package/dist/types/src/model/table-sorting.d.ts.map +0 -1
  161. package/dist/types/src/types/table.d.ts +0 -56
  162. package/dist/types/src/types/table.d.ts.map +0 -1
  163. package/dist/types/src/util/table.d.ts +0 -14
  164. package/dist/types/src/util/table.d.ts.map +0 -1
  165. package/src/components/Table/CreateRefPanel.tsx +0 -84
  166. package/src/components/Table/relations.stories.tsx +0 -123
  167. package/src/components/TableCellEditor/extension.ts +0 -61
  168. package/src/components/TableToolbar/TableToolbar.tsx +0 -102
  169. package/src/components/TableToolbar/index.ts +0 -5
  170. package/src/model/table-sorting.ts +0 -216
  171. package/src/types/table.ts +0 -27
  172. package/src/util/table.ts +0 -127
@@ -2,26 +2,26 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Schema } from 'effect';
5
+ import { type Registry } from '@effect-atom/atom-react';
6
+ import type * as Types from 'effect/Types';
6
7
 
7
- import { Obj, Ref } from '@dxos/echo';
8
- import { getTypename, toJsonSchema } from '@dxos/echo-schema';
9
- import type { JsonSchemaType, SortDirectionType } from '@dxos/echo-schema';
8
+ import { Filter, JsonSchema, Obj, Order, Query, type QueryAST, Ref, Type } from '@dxos/echo';
9
+ import { type View } from '@dxos/echo';
10
10
  import {
11
- createView,
12
- getSchemaFromPropertyDefinitions,
13
- ViewProjection,
14
- type ViewType,
11
+ ProjectionModel,
15
12
  type SchemaPropertyDefinition,
13
+ ViewModel,
14
+ createEchoChangeCallback,
15
+ getSchemaFromPropertyDefinitions,
16
16
  } from '@dxos/schema';
17
17
 
18
- import { TableType } from '../types';
18
+ import { Table } from '../types';
19
19
 
20
20
  // TODO(ZaymonFC): Upstream these extra fields to SchemaPropertyDefinition to enhance schema-tools schema creation.
21
21
  type PropertyDisplayProps = {
22
22
  size: number;
23
23
  title: string;
24
- sort: SortDirectionType;
24
+ sort: QueryAST.OrderDirection;
25
25
  };
26
26
 
27
27
  export type TablePropertyDefinition = SchemaPropertyDefinition & Partial<PropertyDisplayProps>;
@@ -31,21 +31,21 @@ export type TablePropertyDefinition = SchemaPropertyDefinition & Partial<Propert
31
31
  */
32
32
  // TODO(burdon): Remove variance.
33
33
  export const getBaseSchema = ({
34
+ schema,
34
35
  typename,
35
36
  properties,
36
37
  jsonSchema,
37
- schema,
38
38
  }: {
39
+ schema?: Type.AnyEntity;
39
40
  typename?: string;
40
41
  properties?: TablePropertyDefinition[];
41
- jsonSchema?: JsonSchemaType;
42
- schema?: Schema.Schema.AnyNoContext;
43
- }): { typename: string; jsonSchema: JsonSchemaType } => {
42
+ jsonSchema?: Types.DeepMutable<JsonSchema.JsonSchema>;
43
+ }): { typename: string; jsonSchema: Types.DeepMutable<JsonSchema.JsonSchema> } => {
44
44
  if (typename && properties) {
45
45
  const schema = getSchemaFromPropertyDefinitions(typename, properties);
46
- return { typename: schema.typename, jsonSchema: schema.jsonSchema };
46
+ return { typename: schema.typename, jsonSchema: JsonSchema.toJsonSchema(schema) };
47
47
  } else if (schema) {
48
- return { typename: getTypename(schema)!, jsonSchema: toJsonSchema(schema) };
48
+ return { typename: Type.getTypename(schema)!, jsonSchema: JsonSchema.toJsonSchema(schema) };
49
49
  } else if (typename && jsonSchema) {
50
50
  return { typename, jsonSchema };
51
51
  } else {
@@ -54,39 +54,48 @@ export const getBaseSchema = ({
54
54
  };
55
55
 
56
56
  export const makeDynamicTable = ({
57
- typename,
57
+ registry,
58
58
  jsonSchema,
59
59
  properties,
60
60
  }: {
61
- typename: string;
62
- jsonSchema: JsonSchemaType;
61
+ registry: Registry.Registry;
62
+ jsonSchema: Types.DeepMutable<JsonSchema.JsonSchema>;
63
63
  properties?: TablePropertyDefinition[];
64
- }): { table: TableType; projection: ViewProjection } => {
65
- const view = createView({
66
- name: 'dynamic-table',
67
- typename,
64
+ }): { projection: ProjectionModel; object: Table.Table } => {
65
+ const view = ViewModel.make({
66
+ query: Query.select(Filter.everything()),
68
67
  jsonSchema,
69
68
  ...(properties && { fields: properties.map((property) => property.name) }),
70
69
  });
70
+ const object = Obj.make(Table.Table, { view: Ref.make(view), sizes: {} });
71
71
 
72
- const table = Obj.make(TableType, { name: 'dynamic-table', view: Ref.make(view) });
73
- const projection = new ViewProjection(jsonSchema, view);
74
- if (properties && view.fields) {
75
- setProperties(view, projection, properties);
72
+ const projection = new ProjectionModel({
73
+ registry,
74
+ view,
75
+ baseSchema: jsonSchema,
76
+ change: createEchoChangeCallback(view, jsonSchema),
77
+ });
78
+ projection.normalizeView();
79
+ if (properties && projection.getFields()) {
80
+ setProperties(view, projection, object, properties);
76
81
  }
77
82
 
78
- return {
79
- table,
80
- projection,
81
- };
83
+ return { projection, object };
82
84
  };
83
85
 
84
- const setProperties = (view: ViewType, projection: ViewProjection, properties: TablePropertyDefinition[]) => {
86
+ const setProperties = (
87
+ view: View.View,
88
+ projection: ProjectionModel,
89
+ table: Table.Table,
90
+ properties: TablePropertyDefinition[],
91
+ ) => {
85
92
  for (const property of properties) {
86
- const field = view.fields.find((field) => field.path === property.name);
93
+ const field = projection.getFields().find((field) => field.path === property.name);
87
94
  if (field) {
88
95
  if (property.size !== undefined) {
89
- field.size = property.size;
96
+ Obj.change(table, (table) => {
97
+ table.sizes[field.path] = property.size!;
98
+ });
90
99
  }
91
100
 
92
101
  if (property.title !== undefined) {
@@ -98,8 +107,14 @@ const setProperties = (view: ViewType, projection: ViewProjection, properties: T
98
107
  }
99
108
 
100
109
  if (property.sort) {
101
- const fieldId = field.id;
102
- view.query.sort = [{ fieldId, direction: property.sort }];
110
+ // Apply sort to query instead of deprecated view.sort
111
+ const currentQuery = Query.fromAst(Obj.getSnapshot(view).query.ast);
112
+ // Use any type parameter since we're working with dynamic field paths
113
+ const newQuery = currentQuery.orderBy(Order.property<any>(field.path as string, property.sort));
114
+ Obj.change(view, (view) => {
115
+ // Type assertion needed because Query AST types have some variance issues.
116
+ view.query.ast = newQuery.ast as typeof view.query.ast;
117
+ });
103
118
  }
104
119
  }
105
120
  }
package/src/util/index.ts CHANGED
@@ -3,8 +3,9 @@
3
3
  //
4
4
 
5
5
  export * from './dynamic-table';
6
+ export * from './query-ast';
6
7
  export * from './signals';
7
- export * from './table';
8
+ export * from './sort';
8
9
  export * from './table-buttons';
9
10
  export * from './table-controls';
10
11
  export * from './schema';
@@ -0,0 +1,22 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type QueryAST } from '@dxos/echo';
6
+
7
+ /**
8
+ * Extracts order clauses from a query AST.
9
+ * Handles nested structures (options, order, etc.).
10
+ */
11
+ export const extractOrder = (queryAst: QueryAST.Query): readonly QueryAST.Order[] | undefined => {
12
+ if (queryAst.type === 'order') {
13
+ return queryAst.order;
14
+ }
15
+ if (queryAst.type === 'options') {
16
+ return extractOrder(queryAst.query);
17
+ }
18
+ if (queryAst.type === 'from') {
19
+ return extractOrder(queryAst.query);
20
+ }
21
+ return undefined;
22
+ };
@@ -2,8 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
6
- import { isTypeLiteral, TypeLiteral } from 'effect/SchemaAST';
5
+ import * as Schema from 'effect/Schema';
6
+ import * as SchemaAST from 'effect/SchemaAST';
7
7
 
8
8
  /**
9
9
  * Creates a narrowed schema from an original schema that only includes
@@ -20,14 +20,14 @@ export const narrowSchema = <S extends Schema.Schema.AnyNoContext>(
20
20
  ): Schema.Schema<unknown, unknown> | undefined => {
21
21
  const ast = (schema as any)?.ast;
22
22
 
23
- if (isTypeLiteral(ast)) {
23
+ if (SchemaAST.isTypeLiteral(ast)) {
24
24
  // Filter property signatures that match any of the provided paths
25
25
  const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
26
26
 
27
27
  // If we found at least one matching property
28
28
  if (propertySignatures.length > 0) {
29
29
  // Create a new TypeLiteral with only the matching properties
30
- const narrowType = new TypeLiteral(propertySignatures, []);
30
+ const narrowType = new SchemaAST.TypeLiteral(propertySignatures, []);
31
31
  return Schema.make(narrowType);
32
32
  }
33
33
  }
@@ -0,0 +1,90 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Format, type QueryAST } from '@dxos/echo';
6
+
7
+ /**
8
+ * Gets a normalized sort value for a given value and format.
9
+ * This ensures consistent sorting behavior across different data types.
10
+ */
11
+ export const getSortValue = (value: any, format: Format.TypeFormat): any => {
12
+ // Handle null/undefined
13
+ if (value === undefined || value === null) {
14
+ return null;
15
+ }
16
+
17
+ // Handle dates chronologically if schema indicates date format
18
+ const isDateFormat = format === Format.TypeFormat.DateTime || format === Format.TypeFormat.Date;
19
+ if (isDateFormat) {
20
+ const date = new Date(value);
21
+ if (!isNaN(date.getTime())) {
22
+ return date.getTime();
23
+ }
24
+ // Fallback to string if date parsing fails
25
+ return String(value);
26
+ }
27
+
28
+ // Handle numbers if schema indicates number format
29
+ if (
30
+ format === Format.TypeFormat.Number ||
31
+ format === Format.TypeFormat.Integer ||
32
+ format === Format.TypeFormat.Currency ||
33
+ format === Format.TypeFormat.Percent ||
34
+ format === Format.TypeFormat.Duration
35
+ ) {
36
+ const num = typeof value === 'number' ? value : Number(value);
37
+ if (!isNaN(num)) {
38
+ return num;
39
+ }
40
+ // Fallback to string if number parsing fails
41
+ return String(value);
42
+ }
43
+
44
+ // Default to string comparison
45
+ if (typeof value === 'string') {
46
+ return value;
47
+ }
48
+ if (typeof value === 'number') {
49
+ return value;
50
+ }
51
+
52
+ // Fallback to string representation
53
+ return String(value);
54
+ };
55
+
56
+ /**
57
+ * Compares two values for sorting based on the field format.
58
+ * Handles dates, numbers, and strings appropriately.
59
+ */
60
+ export const compareValues = (
61
+ aValue: any,
62
+ bValue: any,
63
+ format: Format.TypeFormat,
64
+ direction: QueryAST.OrderDirection,
65
+ ): number => {
66
+ // Handle null/undefined values - nulls sort to the end
67
+ if (aValue === undefined || aValue === null) {
68
+ return bValue === undefined || bValue === null ? 0 : 1;
69
+ }
70
+ if (bValue === undefined || bValue === null) {
71
+ return -1;
72
+ }
73
+
74
+ // Get normalized sort values
75
+ const aSortValue = getSortValue(aValue, format);
76
+ const bSortValue = getSortValue(bValue, format);
77
+
78
+ // Compare based on type
79
+ let comparison = 0;
80
+ if (typeof aSortValue === 'number' && typeof bSortValue === 'number') {
81
+ comparison = aSortValue - bSortValue;
82
+ } else if (typeof aSortValue === 'string' && typeof bSortValue === 'string') {
83
+ comparison = aSortValue.localeCompare(bSortValue);
84
+ } else {
85
+ // Mixed types - convert both to strings
86
+ comparison = String(aSortValue).localeCompare(String(bSortValue));
87
+ }
88
+
89
+ return direction === 'desc' ? -comparison : comparison;
90
+ };
@@ -26,7 +26,7 @@ const createButton = ({
26
26
  disabled = false,
27
27
  icon,
28
28
  testId,
29
- type = 'primary',
29
+ type: _type = 'primary',
30
30
  }: {
31
31
  attr: string;
32
32
  data: Record<string, string>;
@@ -39,8 +39,7 @@ const createButton = ({
39
39
  .map(([k, v]) => `${k}="${v}"`)
40
40
  .join(' ');
41
41
 
42
- const positionClass = type === 'primary' ? 'inline-end-2' : 'inline-end-9';
43
- return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? 'disabled' : ''}><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
42
+ return `<button ${attr} data-testid="${testId}" class="dx-button w-6 aspect-square px-0.5 min-h-0" ${dataAttrs} ${disabled ? 'disabled' : ''} data-dx-grid-action="accessory"><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
44
43
  };
45
44
 
46
45
  const addColumnButton = {
@@ -67,6 +66,7 @@ const columnSettingsButton = {
67
66
  icon: columnSettingsButton.icon,
68
67
  data: {
69
68
  'data-field-id': fieldId,
69
+ 'data-variant': 'ghost',
70
70
  },
71
71
  testId: 'table-column-settings-button',
72
72
  });
@@ -130,6 +130,7 @@ const saveDraftRowButton = {
130
130
  disabled,
131
131
  data: {
132
132
  'data-row-index': rowIndex.toString(),
133
+ 'data-variant': 'primary',
133
134
  },
134
135
  testId: 'table-save-draft-row-button',
135
136
  });
@@ -3,6 +3,8 @@
3
3
  //
4
4
 
5
5
  // Core types.
6
+ import { accessoryHandlesPointerdownAttrs } from '@dxos/lit-grid';
7
+
6
8
  export type TableControl = 'checkbox' | 'switch';
7
9
 
8
10
  export type ControlData =
@@ -23,8 +25,8 @@ export const CONTROL_IDENTIFIERS = {
23
25
  } as const;
24
26
 
25
27
  const BASE_CLASSES = {
26
- checkbox: 'absolute inset-block-[.375rem] inline-end-[.375rem] dx-checkbox',
27
- switch: 'absolute inset-block-[.25rem] inline-end-[.25rem] dx-checkbox--switch',
28
+ checkbox: 'absolute inset-y-[.375rem] end-[.375rem] dx-checkbox',
29
+ switch: 'absolute inset-y-[.25rem] end-[.25rem] dx-checkbox--switch',
28
30
  } as const;
29
31
 
30
32
  const renderAttributes = (data: Record<string, string>) => {
@@ -41,7 +43,7 @@ const renderInput = (
41
43
  preventToggle = false,
42
44
  testId: string,
43
45
  ) => {
44
- return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? 'checked' : ''} ${preventToggle ? 'onclick="return false"' : ''} ${disabled ? 'disabled' : ''} data-testid="${testId}"/>`;
46
+ return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? 'checked' : ''} ${preventToggle ? 'onclick="return false"' : ''} ${disabled ? 'disabled' : ''} data-testid="${testId}" data-dx-grid-action="accessory"/>`;
45
47
  };
46
48
 
47
49
  export const CheckboxStory = ({
@@ -64,6 +66,7 @@ export const SwitchStory = ({ colIndex, rowIndex, checked = false, disabled = fa
64
66
  [CONTROL_IDENTIFIERS.switch]: '',
65
67
  'data-row-index': rowIndex.toString(),
66
68
  'data-col-index': colIndex.toString(),
69
+ ...accessoryHandlesPointerdownAttrs,
67
70
  };
68
71
 
69
72
  return renderInput(BASE_CLASSES.switch, attrs, checked, disabled, true, 'table-switch');
@@ -1,27 +0,0 @@
1
- // src/types/table.ts
2
- import { Schema } from "effect";
3
- import { Type } from "@dxos/echo";
4
- import { ObjectId, Ref, Expando, LabelAnnotation } from "@dxos/echo-schema";
5
- import { ViewType } from "@dxos/schema";
6
- var TableSchema = Schema.Struct({
7
- id: ObjectId,
8
- name: Schema.optional(Schema.String),
9
- view: Schema.optional(Ref(ViewType)),
10
- // TODO(burdon): Document why threads is included here?
11
- threads: Schema.optional(Schema.Array(Ref(
12
- Expando
13
- /* ThreadType */
14
- )))
15
- }).pipe(LabelAnnotation.set([
16
- "name"
17
- ]));
18
- var TableType = TableSchema.pipe(Type.Obj({
19
- typename: "dxos.org/type/Table",
20
- version: "0.1.0"
21
- }));
22
-
23
- export {
24
- TableSchema,
25
- TableType
26
- };
27
- //# sourceMappingURL=chunk-Q5QQXJUO.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema } from 'effect';\n\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { Type } from '@dxos/echo';\nimport { ObjectId, Ref, Expando, LabelAnnotation } from '@dxos/echo-schema';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = Schema.Struct({\n id: ObjectId,\n name: Schema.optional(Schema.String),\n view: Schema.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),\n}).pipe(LabelAnnotation.set(['name']));\n\n// TODO(burdon): Move out of react-ui-xxx.\nexport const TableType = TableSchema.pipe(\n Type.Obj({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n }),\n);\nexport interface TableType extends Schema.Schema.Type<typeof TableType> {}\n"],
5
- "mappings": ";AAIA,SAASA,cAAc;AAGvB,SAASC,YAAY;AACrB,SAASC,UAAUC,KAAKC,SAASC,uBAAuB;AACxD,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,OAAOC,OAAO;EACvCC,IAAIC;EACJC,MAAMJ,OAAOK,SAASL,OAAOM,MAAM;EACnCC,MAAMP,OAAOK,SAASG,IAAIC,QAAAA,CAAAA;;EAE1BC,SAASV,OAAOK,SAASL,OAAOW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AAClE,CAAA,EAAGC,KAAKC,gBAAgBC,IAAI;EAAC;CAAO,CAAA;AAG7B,IAAMC,YAAYjB,YAAYc,KACnCI,KAAKC,IAAI;EACPC,UAAU;EACVC,SAAS;AACX,CAAA,CAAA;",
6
- "names": ["Schema", "Type", "ObjectId", "Ref", "Expando", "LabelAnnotation", "ViewType", "TableSchema", "Schema", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "pipe", "LabelAnnotation", "set", "TableType", "Type", "Obj", "typename", "version"]
7
- }
@@ -1,29 +0,0 @@
1
- import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
-
3
- // src/types/table.ts
4
- import { Schema } from "effect";
5
- import { Type } from "@dxos/echo";
6
- import { ObjectId, Ref, Expando, LabelAnnotation } from "@dxos/echo-schema";
7
- import { ViewType } from "@dxos/schema";
8
- var TableSchema = Schema.Struct({
9
- id: ObjectId,
10
- name: Schema.optional(Schema.String),
11
- view: Schema.optional(Ref(ViewType)),
12
- // TODO(burdon): Document why threads is included here?
13
- threads: Schema.optional(Schema.Array(Ref(
14
- Expando
15
- /* ThreadType */
16
- )))
17
- }).pipe(LabelAnnotation.set([
18
- "name"
19
- ]));
20
- var TableType = TableSchema.pipe(Type.Obj({
21
- typename: "dxos.org/type/Table",
22
- version: "0.1.0"
23
- }));
24
-
25
- export {
26
- TableSchema,
27
- TableType
28
- };
29
- //# sourceMappingURL=chunk-ZNOU6LHG.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema } from 'effect';\n\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { Type } from '@dxos/echo';\nimport { ObjectId, Ref, Expando, LabelAnnotation } from '@dxos/echo-schema';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = Schema.Struct({\n id: ObjectId,\n name: Schema.optional(Schema.String),\n view: Schema.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),\n}).pipe(LabelAnnotation.set(['name']));\n\n// TODO(burdon): Move out of react-ui-xxx.\nexport const TableType = TableSchema.pipe(\n Type.Obj({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n }),\n);\nexport interface TableType extends Schema.Schema.Type<typeof TableType> {}\n"],
5
- "mappings": ";;;AAIA,SAASA,cAAc;AAGvB,SAASC,YAAY;AACrB,SAASC,UAAUC,KAAKC,SAASC,uBAAuB;AACxD,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,OAAOC,OAAO;EACvCC,IAAIC;EACJC,MAAMJ,OAAOK,SAASL,OAAOM,MAAM;EACnCC,MAAMP,OAAOK,SAASG,IAAIC,QAAAA,CAAAA;;EAE1BC,SAASV,OAAOK,SAASL,OAAOW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AAClE,CAAA,EAAGC,KAAKC,gBAAgBC,IAAI;EAAC;CAAO,CAAA;AAG7B,IAAMC,YAAYjB,YAAYc,KACnCI,KAAKC,IAAI;EACPC,UAAU;EACVC,SAAS;AACX,CAAA,CAAA;",
6
- "names": ["Schema", "Type", "ObjectId", "Ref", "Expando", "LabelAnnotation", "ViewType", "TableSchema", "Schema", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "pipe", "LabelAnnotation", "set", "TableType", "Type", "Obj", "typename", "version"]
7
- }
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { type GridScopedProps } from '@dxos/react-ui-grid';
3
- import { type TableModel, type ModalController } from '../../model';
4
- export type CreateRefPanelProps = {
5
- model?: TableModel;
6
- modals: ModalController;
7
- };
8
- export declare const CreateRefPanel: ({ model, modals, __gridScope }: GridScopedProps<CreateRefPanelProps>) => React.JSX.Element | null;
9
- //# sourceMappingURL=CreateRefPanel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CreateRefPanel.d.ts","sourceRoot":"","sources":["../../../../../src/components/Table/CreateRefPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAKpD,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpE,MAAM,MAAM,mBAAmB,GAAG;IAAE,KAAK,CAAC,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC;AAGlF,eAAO,MAAM,cAAc,GAAI,gCAAgC,eAAe,CAAC,mBAAmB,CAAC,6BAkElG,CAAC"}
@@ -1,9 +0,0 @@
1
- import '@dxos-theme';
2
- import { type StoryObj, type Meta } from '@storybook/react-vite';
3
- import React from 'react';
4
- declare const DefaultStory: () => React.JSX.Element;
5
- declare const meta: Meta<typeof DefaultStory>;
6
- export default meta;
7
- type Story = StoryObj<typeof DefaultStory>;
8
- export declare const Default: Story;
9
- //# sourceMappingURL=relations.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"relations.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Table/relations.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,KAA6B,MAAM,OAAO,CAAC;AA8ElD,QAAA,MAAM,YAAY,yBAejB,CAAC;AAEF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,YAAY,CAanC,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,YAAY,CAAC,CAAC;AAE3C,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC"}
@@ -1,13 +0,0 @@
1
- import { type CompletionResult } from '@codemirror/autocomplete';
2
- import { type Extension } from '@codemirror/state';
3
- export type CompletionOptions = {
4
- debug?: boolean;
5
- onQuery: (text: string) => Promise<CompletionResult['options']>;
6
- onMatch: (data: any) => void;
7
- };
8
- /**
9
- * Autocomplete Codemirror extension.
10
- * https://codemirror.net/docs/ref/#autocomplete.autocompletion
11
- */
12
- export declare const completion: ({ debug, onQuery, onMatch }: CompletionOptions) => Extension;
13
- //# sourceMappingURL=extension.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../../src/components/TableCellEditor/extension.ts"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;IAChE,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,6BAA6B,iBAAiB,KAAG,SAqC3E,CAAC"}
@@ -1,21 +0,0 @@
1
- import { Rx } from '@effect-rx/rx-react';
2
- import React from 'react';
3
- import { type ThemedClassName } from '@dxos/react-ui';
4
- import { type ActionGraphProps, type MenuAction } from '@dxos/react-ui-menu';
5
- export type TableToolbarActionProperties = {
6
- type: TableToolbarActionType;
7
- };
8
- export type TableToolbarAction = MenuAction<TableToolbarActionProperties>;
9
- export type TableToolbarActionType = 'add-row' | 'comment' | 'save-view';
10
- type TableToolbarState = Partial<{
11
- viewDirty: boolean;
12
- }>;
13
- export type TableToolbarProps = ThemedClassName<TableToolbarState & {
14
- onAdd: () => void;
15
- onSave: () => void;
16
- attendableId?: string;
17
- customActions?: Rx.Rx<ActionGraphProps>;
18
- }>;
19
- export declare const TableToolbar: ({ classNames, viewDirty, attendableId, onAdd, onSave, customActions, }: TableToolbarProps) => React.JSX.Element;
20
- export {};
21
- //# sourceMappingURL=TableToolbar.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TableToolbar.d.ts","sourceRoot":"","sources":["../../../../../src/components/TableToolbar/TableToolbar.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AACzC,OAAO,KAAkB,MAAM,OAAO,CAAC;AAGvC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAGL,KAAK,gBAAgB,EAGrB,KAAK,UAAU,EAIhB,MAAM,qBAAqB,CAAC;AAK7B,MAAM,MAAM,4BAA4B,GAAG;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAE5E,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,4BAA4B,CAAC,CAAC;AAE1E,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEzE,KAAK,iBAAiB,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEzD,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAC7C,iBAAiB,GAAG;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;CACzC,CACF,CAAC;AA0CF,eAAO,MAAM,YAAY,GAAI,wEAO1B,iBAAiB,sBAanB,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './TableToolbar';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/TableToolbar/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC"}
@@ -1,53 +0,0 @@
1
- import { type Signal, type ReadonlySignal } from '@preact/signals-core';
2
- import { type SortDirectionType, type FieldSortType } from '@dxos/echo-schema';
3
- import type { ViewProjection, ViewType } from '@dxos/schema';
4
- import { type TableRow } from './table-model';
5
- /**
6
- * Manages table sorting functionality through display and data index mapping.
7
- *
8
- * When a table is sorted, rows visually reorder but we need to maintain references
9
- * to the original data positions. This is handled through two types of indices:
10
- *
11
- * - Display indices: The visual positions after sorting
12
- * - Data indices: The original positions in the source data
13
- *
14
- * The _displayToDataIndex map maintains these relationships, enabling lookups
15
- * between visual and source positions.
16
- *
17
- * Example mapping between display and data indices:
18
- *
19
- * Original Data: Sorted Display: Mapping: (Display → Data)
20
- * ┌──────────────┐ ┌──────────────┐ ┌────────┐
21
- * │ 0: "Banana" │ => │ 0: "Apple" │ => │ 0 => 1 │
22
- * │ 1: "Apple" │ => │ 1: "Banana" │ => │ 1 => 0 │
23
- * │ 2: "Cherry" │ => │ 2: "Cherry" │ => │ 2 => 2 │
24
- * └──────────────┘ └──────────────┘ └────────┘
25
- */
26
- export declare class TableSorting<T extends TableRow> {
27
- private readonly _view;
28
- private readonly _projection;
29
- private readonly _displayToDataIndex;
30
- private readonly _rows;
31
- private readonly _localSort;
32
- private readonly _isDirty;
33
- readonly sortedRows: ReadonlySignal<T[]>;
34
- constructor(rows: Signal<T[]>, _view: ViewType | undefined, _projection: ViewProjection);
35
- /**
36
- * @reactive
37
- * @returns Local sort if present, falls back to view sort.
38
- */
39
- get sorting(): FieldSortType | undefined;
40
- /**
41
- * @reactive
42
- * @returns Whether local sort differs from view sort.
43
- */
44
- get isDirty(): boolean;
45
- getDataIndex(displayIndex: number): number;
46
- setSort(fieldId: string, direction: SortDirectionType): void;
47
- toggleSort(fieldId: string): void;
48
- clearSort(): void;
49
- save(): void;
50
- private initialiseSortedRows;
51
- private getSortValue;
52
- }
53
- //# sourceMappingURL=table-sorting.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"table-sorting.d.ts","sourceRoot":"","sources":["../../../../src/model/table-sorting.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoB,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG1F,OAAO,EAAkC,KAAK,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE/G,OAAO,KAAK,EAA2B,cAAc,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEtF,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAU9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAY,CAAC,CAAC,SAAS,QAAQ;IASxC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAT9B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA6B;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0B;IACnD,SAAgB,UAAU,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;gBAG9C,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EACA,KAAK,EAAE,QAAQ,GAAG,SAAS,EAC3B,WAAW,EAAE,cAAc;IAoB9C;;;OAGG;IACH,IAAW,OAAO,IAAI,aAAa,GAAG,SAAS,CAU9C;IAED;;;OAGG;IACH,IAAW,OAAO,IAAI,OAAO,CAE5B;IAEM,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAI1C,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,GAAG,IAAI;IAO5D,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAiBjC,SAAS,IAAI,IAAI;IAIjB,IAAI,IAAI,IAAI;IAenB,OAAO,CAAC,oBAAoB;IAkC5B,OAAO,CAAC,YAAY;CAsCrB"}