@airtable/blocks 0.0.0-experimental-28533a19d-20251016 → 0.0.0-experimental-a1a13b445-20251124

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.
@@ -1,7 +1,7 @@
1
1
  /** @module @airtable/blocks/models: Record */ /** */
2
2
 
3
- import { RecordCore, WatchableRecordKeysCore } from '../../shared/models/record_core';
4
- import { isEnumValue, isObjectEmpty } from '../../shared/private_utils';
3
+ import { RecordCore, WatchableCellValueInFieldKeyPrefix, WatchableRecordKeysCore } from '../../shared/models/record_core';
4
+ import { isEnumValue } from '../../shared/private_utils';
5
5
  import { invariant } from '../../shared/error_utils';
6
6
  import colorUtils from '../../shared/color_utils';
7
7
  import LinkedRecordsQueryResult from './linked_records_query_result';
@@ -11,11 +11,9 @@ const WatchableRecordKeys = Object.freeze({
11
11
  ...WatchableRecordKeysCore,
12
12
  commentCount: 'commentCount'
13
13
  });
14
- // TODO: load cell values in field when this is watched? This will
15
- // cause the CellRenderer component to load cell values, which seems okay,
16
- // but needs a little more thought.
17
- const WatchableCellValueInFieldKeyPrefix = 'cellValueInField:';
18
- // TODO: load view data when this is watched. see previous comment.
14
+
15
+ // TODO: Should we load view data when this is watched?
16
+ // See comment on WatchableCellValueInFieldKeyPrefix.
19
17
  const WatchableColorInViewKeyPrefix = 'colorInView:';
20
18
  /**
21
19
  * Any key within record that can be watched:
@@ -210,14 +208,8 @@ class Record extends RecordCore {
210
208
  __triggerOnChangeForDirtyPaths(dirtyPaths) {
211
209
  super.__triggerOnChangeForDirtyPaths(dirtyPaths);
212
210
  const {
213
- cellValuesByFieldId,
214
211
  commentCount
215
212
  } = dirtyPaths;
216
- if (cellValuesByFieldId && !isObjectEmpty(cellValuesByFieldId)) {
217
- for (const fieldId of Object.keys(cellValuesByFieldId)) {
218
- this._onChange(WatchableCellValueInFieldKeyPrefix + fieldId, fieldId);
219
- }
220
- }
221
213
  if (commentCount) {
222
214
  this._onChange(WatchableRecordKeys.commentCount);
223
215
  }
@@ -1,5 +1,6 @@
1
1
  import { spawnError } from '../../shared/error_utils';
2
- import { RecordCore, WatchableRecordKeysCore } from '../../shared/models/record_core';
2
+ import { RecordCore, WatchableCellValueInFieldKeyPrefix, WatchableRecordKeysCore } from '../../shared/models/record_core';
3
+ import { isEnumValue } from '../../shared/private_utils';
3
4
  import { FieldType } from '../../shared/types/field_core';
4
5
  const WatchableRecordKeys = Object.freeze({
5
6
  ...WatchableRecordKeysCore
@@ -8,6 +9,7 @@ const WatchableRecordKeys = Object.freeze({
8
9
  * Any key within record that can be watched:
9
10
  * - `'name'`
10
11
  * - `'cellValues'`
12
+ * - `'cellValueInField:' + someFieldId`
11
13
  */
12
14
 
13
15
  /**
@@ -20,6 +22,10 @@ const WatchableRecordKeys = Object.freeze({
20
22
  export class Record extends RecordCore {
21
23
  /** @internal */
22
24
  static _className = 'Record';
25
+ /** @internal */
26
+ static _isWatchableKey(key) {
27
+ return isEnumValue(WatchableRecordKeys, key) || key.startsWith(WatchableCellValueInFieldKeyPrefix);
28
+ }
23
29
 
24
30
  /**
25
31
  * Fetch foreign records for a field. Subsequent calls to this method will
@@ -68,4 +68,25 @@ export class InterfaceBlockSdk extends BlockSdkCore {
68
68
  setCustomPropertiesAsync(properties) {
69
69
  return this.__airtableInterface.setCustomPropertiesAsync(properties);
70
70
  }
71
+
72
+ /**
73
+ * @internal
74
+ */
75
+ setSelectedSubElementAsync(selectedSubElement) {
76
+ return this.__airtableInterface.setSelectedSubElementAsync(selectedSubElement);
77
+ }
78
+
79
+ /**
80
+ * @internal
81
+ */
82
+ fetchAndSubscribeToSelectionDataAsync(callback) {
83
+ return this.__airtableInterface.fetchAndSubscribeToSelectionDataAsync(callback);
84
+ }
85
+
86
+ /**
87
+ * @internal
88
+ */
89
+ unsubscribeFromSelectionData() {
90
+ return this.__airtableInterface.unsubscribeFromSelectionData();
91
+ }
71
92
  }
@@ -30,6 +30,10 @@ export let BlockInstallationPageElementCustomPropertyTypeForAirtableInterface =
30
30
  // https://github.com/Hyperbase/hyperbase/blob/2c0e2ef2cbc6bce7ab33fd913ef3572a83c3892d/client_server_shared/pages/types/block_installation_page_elements/block_installation_page_element_custom_properties_types.tsx
31
31
  /** @hidden */
32
32
 
33
+ /** @hidden */
34
+
35
+ /** @hidden */
36
+
33
37
  /**
34
38
  * AirtableInterface is designed as the communication interface between the
35
39
  * Block SDK and Airtable.
@@ -0,0 +1,409 @@
1
+ /** @module @airtable/blocks/interface/ui: SelectableWrapper */ /** */
2
+ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
3
+ import ReactDOM from 'react-dom';
4
+ import { useSdk } from '../../shared/ui/sdk_context';
5
+ import { useRunInfo } from './use_run_info';
6
+
7
+ /**
8
+ * Context to track the nesting depth of SelectableWrapper components.
9
+ * Used to ensure child overlays render above parent overlays via z-index.
10
+ *
11
+ * @internal
12
+ */
13
+ const NestingDepthContext = /*#__PURE__*/React.createContext(0);
14
+
15
+ /** @hidden */
16
+
17
+ /**
18
+ * A wrapper component that makes its child selectable with a click overlay.
19
+ * When clicked, the child component is marked as selected. If already selected,
20
+ * the overlay becomes click-through. Selected elements display a blue border.
21
+ *
22
+ * @component
23
+ * @hidden
24
+ */
25
+ export function SelectableWrapper(_ref) {
26
+ let {
27
+ children,
28
+ sourceLocation,
29
+ name
30
+ } = _ref;
31
+ const runInfo = useRunInfo();
32
+ if (runInfo.isPageElementInEditMode) {
33
+ return /*#__PURE__*/React.createElement(SelectableWrapperInEditMode, {
34
+ sourceLocation: sourceLocation,
35
+ name: name
36
+ }, children);
37
+ } else {
38
+ return /*#__PURE__*/React.createElement(SelectableWrapperInViewMode, {
39
+ name: name
40
+ }, children);
41
+ }
42
+ }
43
+
44
+ /** @internal */
45
+ function SelectableWrapperInViewMode(_ref2) {
46
+ let {
47
+ children
48
+ } = _ref2;
49
+ return children;
50
+ }
51
+
52
+ /** @internal */
53
+ function SelectableWrapperInEditMode(_ref3) {
54
+ let {
55
+ children,
56
+ sourceLocation,
57
+ name
58
+ } = _ref3;
59
+ const id = useUniqueId();
60
+ const [ref, setRef] = useState(null);
61
+ const sdk = useSdk();
62
+
63
+ // Get the current nesting depth from context
64
+ const nestingDepth = useContext(NestingDepthContext);
65
+
66
+ // Check if this wrapper is currently selected
67
+ const selectionData = useSelectedSubElementId();
68
+ const isSelected = selectionData.selectedSubElementId === id;
69
+
70
+ // Handle overlay click
71
+ const handleOverlayClick = async event => {
72
+ event.preventDefault();
73
+ event.stopPropagation();
74
+
75
+ // Only handle selection if not already selected
76
+ if (!isSelected) {
77
+ await sdk.setSelectedSubElementAsync({
78
+ subElementId: id,
79
+ sourceLocation,
80
+ name
81
+ });
82
+ }
83
+ };
84
+ useEffect(() => {
85
+ if (!isSelected) {
86
+ return () => {};
87
+ }
88
+
89
+ // Add a global click listener to deselect this SelectableWrapper if there
90
+ // is a click outside it
91
+ const globalClickListener = async event => {
92
+ // Check if the click is outside this SelectableWrapper div
93
+ const isClickOutside = event.target instanceof Node && ref && !ref.contains(event.target);
94
+
95
+ // Check if the click is on another SelectableWrapper's overlay
96
+ const isClickOnOtherWrapper = event.target instanceof HTMLElement && event.target.dataset.selectableWrapperOverlay === 'true';
97
+ if (isClickOutside && !isClickOnOtherWrapper) {
98
+ // In this case, notify liveapp to deselect this sub element. The deselection
99
+ // originated from the SDK.
100
+ await sdk.setSelectedSubElementAsync(null);
101
+ }
102
+ };
103
+ const globalClickListenerOptions = {
104
+ // Use capture phase to ensure the click is handled even if stopPropagation is called.
105
+ // This is necessary because the click event is triggered by a click on some other overlay,
106
+ // the overlay calls stopPropagation.
107
+ capture: true
108
+ };
109
+ document.addEventListener('click', globalClickListener, globalClickListenerOptions);
110
+ return () => {
111
+ document.removeEventListener('click', globalClickListener, globalClickListenerOptions);
112
+ };
113
+ }, [sdk, isSelected, ref]);
114
+
115
+ // Track the latest isSelected value in a ref for use in unmount cleanup
116
+ const isSelectedRef = useRef(isSelected);
117
+ // Keep the ref in sync with isSelected
118
+ useEffect(() => {
119
+ isSelectedRef.current = isSelected;
120
+ }, [isSelected]);
121
+ // If the component unmounts while selected, deselect it. We use a ref to track
122
+ // isSelected so that changes to isSelected don't cause this effect to re-run.
123
+ // This effect should only run its cleanup when the component actually unmounts.
124
+ useEffect(() => {
125
+ return () => {
126
+ if (isSelectedRef.current) {
127
+ sdk.setSelectedSubElementAsync(null);
128
+ }
129
+ };
130
+ }, [sdk]);
131
+ return /*#__PURE__*/React.createElement(NestingDepthContext.Provider, {
132
+ value: nestingDepth + 1
133
+ }, /*#__PURE__*/React.createElement("div", {
134
+ ref: setRef,
135
+ style: {
136
+ display: 'contents'
137
+ }
138
+ }, children, /*#__PURE__*/React.createElement(Overlay, {
139
+ wrapperDiv: ref,
140
+ isSelected: isSelected,
141
+ ariaLabel: `Select ${name || 'element'}`,
142
+ onClick: handleOverlayClick,
143
+ nestingDepth: nestingDepth
144
+ })));
145
+ }
146
+
147
+ /**
148
+ * Traverses ancestors once to gather both z-index and scrollable containers.
149
+ * Returns the effective z-index and an array of scrollable ancestor elements.
150
+ *
151
+ * @internal
152
+ */
153
+ function getAncestorInfo(element) {
154
+ const scrollableAncestors = [];
155
+ let effectiveZIndex = 0;
156
+ let current = element.parentElement;
157
+ while (current && current !== document.body) {
158
+ const style = window.getComputedStyle(current);
159
+
160
+ // Check for effective z-index (only if we haven't found one yet)
161
+ if (effectiveZIndex === 0) {
162
+ const zIndex = parseInt(style.zIndex, 10);
163
+ if (!isNaN(zIndex) && style.position !== 'static') {
164
+ effectiveZIndex = zIndex;
165
+ }
166
+ }
167
+
168
+ // Check if this ancestor is scrollable
169
+ const isScrollable = [style.overflow, style.overflowX, style.overflowY].some(overflow => overflow === 'auto' || overflow === 'scroll');
170
+ if (isScrollable) {
171
+ scrollableAncestors.push(current);
172
+ }
173
+ current = current.parentElement;
174
+ }
175
+ return {
176
+ effectiveZIndex,
177
+ scrollableAncestors
178
+ };
179
+ }
180
+
181
+ /** @internal */
182
+ function Overlay(_ref4) {
183
+ let {
184
+ wrapperDiv,
185
+ isSelected,
186
+ ariaLabel,
187
+ onClick,
188
+ nestingDepth
189
+ } = _ref4;
190
+ const [boundingClientRect, setBoundingClientRect] = useState(null);
191
+
192
+ // Limitation: We currently only compute this once (for a given identity
193
+ // of wrapperDiv), which means that
194
+ // - if wrapperDiv or an ancestor is reparented, or
195
+ // - if the z-index or scrollability of an ancestor changes
196
+ // then these values will be stale.
197
+ // In practice, reparenting DOM elements is rare in React apps.
198
+ // TBD how common z-index or scrollability changes are in practice - it's
199
+ // something we should keep an eye on.
200
+ const {
201
+ baseZIndex,
202
+ scrollableAncestors
203
+ } = useMemo(() => {
204
+ if (!wrapperDiv) {
205
+ return {
206
+ baseZIndex: 0,
207
+ scrollableAncestors: []
208
+ };
209
+ }
210
+ const {
211
+ effectiveZIndex,
212
+ scrollableAncestors
213
+ } = getAncestorInfo(wrapperDiv);
214
+ return {
215
+ baseZIndex: effectiveZIndex,
216
+ scrollableAncestors
217
+ };
218
+ }, [wrapperDiv]);
219
+ useEffect(() => {
220
+ if (!wrapperDiv) {
221
+ return () => {};
222
+ }
223
+
224
+ // Function to compute the aggregate bounding client rect
225
+ const computeBoundingRect = () => {
226
+ if (!wrapperDiv) {
227
+ return null;
228
+ }
229
+ let aggregateBoundingClientRect = null;
230
+ for (const child of wrapperDiv.children) {
231
+ const boundingClientRect = child.getBoundingClientRect();
232
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
233
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
234
+ if (!aggregateBoundingClientRect) {
235
+ aggregateBoundingClientRect = {
236
+ left: boundingClientRect.left + scrollLeft,
237
+ top: boundingClientRect.top + scrollTop,
238
+ right: boundingClientRect.right + scrollLeft,
239
+ bottom: boundingClientRect.bottom + scrollTop
240
+ };
241
+ continue;
242
+ }
243
+ if (boundingClientRect.left + scrollLeft < aggregateBoundingClientRect.left) {
244
+ aggregateBoundingClientRect.left = boundingClientRect.left + scrollLeft;
245
+ }
246
+ if (boundingClientRect.top + scrollTop < aggregateBoundingClientRect.top) {
247
+ aggregateBoundingClientRect.top = boundingClientRect.top + scrollTop;
248
+ }
249
+ if (boundingClientRect.right + scrollLeft > aggregateBoundingClientRect.right) {
250
+ aggregateBoundingClientRect.right = boundingClientRect.right + scrollLeft;
251
+ }
252
+ if (boundingClientRect.bottom + scrollTop > aggregateBoundingClientRect.bottom) {
253
+ aggregateBoundingClientRect.bottom = boundingClientRect.bottom + scrollTop;
254
+ }
255
+ }
256
+ return aggregateBoundingClientRect;
257
+ };
258
+
259
+ // Initial computation
260
+ const rect = computeBoundingRect();
261
+ setBoundingClientRect(rect);
262
+
263
+ // Debounce helper
264
+ let resizeTimeoutId = null;
265
+ const debouncedUpdateRect = () => {
266
+ // Immediately reset the bounding client rect to null when the window is resized
267
+ // to avoid the overlay being in the wrong position as the resize is happening.
268
+ // Then debounce the actual measurement with setTimeout for performance.
269
+ setBoundingClientRect(null);
270
+ if (resizeTimeoutId !== null) {
271
+ clearTimeout(resizeTimeoutId);
272
+ }
273
+ resizeTimeoutId = setTimeout(() => {
274
+ const updatedRect = computeBoundingRect();
275
+ setBoundingClientRect(updatedRect);
276
+ resizeTimeoutId = null;
277
+ }, 16); // ~60fps
278
+ };
279
+
280
+ // Set up ResizeObserver to watch for size changes (debounced)
281
+ const resizeObserver = new ResizeObserver(debouncedUpdateRect);
282
+
283
+ // Observe resize on the wrapper element and all its children
284
+ resizeObserver.observe(wrapperDiv);
285
+ for (const child of wrapperDiv.children) {
286
+ resizeObserver.observe(child);
287
+ }
288
+
289
+ // Set up MutationObserver to watch for changes to children
290
+ const mutationObserver = new MutationObserver(() => {
291
+ const updatedRect = computeBoundingRect();
292
+ setBoundingClientRect(updatedRect);
293
+
294
+ // Re-observe all children with the ResizeObserver in case new children were added
295
+ // This ensures dynamically added children are also observed for resize events
296
+ resizeObserver.disconnect();
297
+ resizeObserver.observe(wrapperDiv);
298
+ for (const child of wrapperDiv.children) {
299
+ resizeObserver.observe(child);
300
+ }
301
+ });
302
+
303
+ // Observe changes to child list and subtree (e.g., attributes, content)
304
+ mutationObserver.observe(wrapperDiv, {
305
+ childList: true,
306
+ subtree: true,
307
+ attributes: true,
308
+ characterData: true
309
+ });
310
+
311
+ // Listen for window resize events to catch viewport changes (debounced)
312
+ window.addEventListener('resize', debouncedUpdateRect);
313
+
314
+ // Listen for scroll events on scrollable ancestor containers
315
+ // Note: We don't need to listen to window scroll because the overlay and wrapped
316
+ // element are both positioned relative to the document, so they scroll together naturally.
317
+ // We only need to listen to scrollable containers because the overlay is portaled
318
+ // outside them to document.body, so it won't scroll with them automatically.
319
+ // Use passive: true for better scroll performance
320
+ scrollableAncestors.forEach(scrollable => {
321
+ scrollable.addEventListener('scroll', debouncedUpdateRect, {
322
+ passive: true
323
+ });
324
+ });
325
+ return () => {
326
+ if (resizeTimeoutId !== null) {
327
+ clearTimeout(resizeTimeoutId);
328
+ }
329
+ mutationObserver.disconnect();
330
+ resizeObserver.disconnect();
331
+ window.removeEventListener('resize', debouncedUpdateRect);
332
+ scrollableAncestors.forEach(scrollable => {
333
+ scrollable.removeEventListener('scroll', debouncedUpdateRect);
334
+ });
335
+ };
336
+ }, [wrapperDiv, scrollableAncestors]);
337
+ const [isHovered, setIsHovered] = useState(false);
338
+ const handleMouseEnter = () => {
339
+ setIsHovered(true);
340
+ };
341
+ const handleMouseLeave = () => {
342
+ setIsHovered(false);
343
+ };
344
+ if (!boundingClientRect) {
345
+ return null;
346
+ }
347
+ return /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement("div", {
348
+ onClick: onClick,
349
+ role: "button"
350
+ // Prevent keyboard focus. This is consistent with the behavior of native interface elements
351
+ // in interface designer. See tk tk
352
+ ,
353
+ tabIndex: -1,
354
+ "data-selectable-wrapper-overlay": "true",
355
+ onMouseEnter: handleMouseEnter,
356
+ onMouseLeave: handleMouseLeave,
357
+ "aria-label": ariaLabel,
358
+ style: {
359
+ position: 'absolute',
360
+ left: boundingClientRect.left,
361
+ top: boundingClientRect.top,
362
+ height: boundingClientRect.bottom - boundingClientRect.top,
363
+ width: boundingClientRect.right - boundingClientRect.left,
364
+ backgroundColor: isSelected ? 'transparent' : isHovered ? 'rgba(22, 110, 225, 0.05)' : 'transparent',
365
+ cursor: isSelected ? 'default' : 'pointer',
366
+ pointerEvents: isSelected ? 'none' : 'auto',
367
+ outline: isSelected ? '2px solid #3b82f6' : undefined,
368
+ outlineOffset: isSelected ? '-2px' : undefined,
369
+ // borderRadius: isSelected ? '4px' : undefined,
370
+ // Use base z-index from ancestors + 1 to be above the wrapper + nestingDepth for nested overlays
371
+ zIndex: baseZIndex + 1 + nestingDepth
372
+ }
373
+ }), document.body);
374
+ }
375
+
376
+ /** @internal */
377
+ function useUniqueId() {
378
+ return useMemo(() => Math.random().toString(36).substring(2, 15), []);
379
+ }
380
+
381
+ /** @internal */
382
+ function useSelectedSubElementId() {
383
+ const sdk = useSdk();
384
+ const [selectedSubElementId, setSelectedSubElementId] = useState(null);
385
+ useEffect(() => {
386
+ let isCancelled = false;
387
+ // Subscribe to selection data updates
388
+ const handleSelectionUpdate = data => {
389
+ setSelectedSubElementId(data.selectedSubElementId);
390
+ };
391
+
392
+ // Fetch initial selection data and subscribe to updates
393
+
394
+ sdk.fetchAndSubscribeToSelectionDataAsync(handleSelectionUpdate).then(initialData => {
395
+ if (!isCancelled) {
396
+ setSelectedSubElementId(initialData.selectedSubElementId ?? null);
397
+ }
398
+ });
399
+
400
+ // Cleanup: unsubscribe when component unmounts
401
+ return () => {
402
+ isCancelled = true;
403
+ sdk.unsubscribeFromSelectionData();
404
+ };
405
+ }, [sdk]);
406
+ return {
407
+ selectedSubElementId
408
+ };
409
+ }
@@ -6,6 +6,7 @@ import '..';
6
6
  export { CellRenderer } from './cell_renderer';
7
7
  export { expandRecord } from './expand_record';
8
8
  export { initializeBlock } from './initialize_block';
9
+ export { SelectableWrapper } from './selectable_wrapper';
9
10
  export { useBase } from './use_base';
10
11
  export { useColorScheme } from '../../shared/ui/use_color_scheme';
11
12
  export { useCustomProperties } from './use_custom_properties';
@@ -1,4 +1,4 @@
1
- import { cloneDeep, isEnumValue, isObjectEmpty } from '../private_utils';
1
+ import { cloneDeep, isObjectEmpty } from '../private_utils';
2
2
  import { invariant } from '../error_utils';
3
3
  import { FieldType } from '../types/field_core';
4
4
  import AbstractModel from './abstract_model';
@@ -9,6 +9,10 @@ export const WatchableRecordKeysCore = Object.freeze({
9
9
  // it's just inconsistent...)
10
10
  cellValues: 'cellValues'
11
11
  });
12
+ // TODO: load cell values in field when this is watched? This will
13
+ // cause the CellRenderer component to load cell values, which seems okay,
14
+ // but needs a little more thought.
15
+ export const WatchableCellValueInFieldKeyPrefix = 'cellValueInField:';
12
16
 
13
17
  /** @hidden */
14
18
 
@@ -17,10 +21,6 @@ export class RecordCore extends AbstractModel {
17
21
  /** @internal */
18
22
  static _className = 'RecordCore';
19
23
  /** @internal */
20
- static _isWatchableKey(key) {
21
- return isEnumValue(WatchableRecordKeysCore, key);
22
- }
23
- /** @internal */
24
24
 
25
25
  /** @internal */
26
26
 
@@ -199,6 +199,9 @@ export class RecordCore extends AbstractModel {
199
199
  // that we're not subscribed to).
200
200
 
201
201
  this._onChange(WatchableRecordKeysCore.cellValues, Object.keys(cellValuesByFieldId));
202
+ for (const fieldId of Object.keys(cellValuesByFieldId)) {
203
+ this._onChange(WatchableCellValueInFieldKeyPrefix + fieldId, fieldId);
204
+ }
202
205
  if (cellValuesByFieldId[this.parentTable.primaryField.id]) {
203
206
  this._onChange(WatchableRecordKeysCore.name);
204
207
  }
@@ -24,7 +24,7 @@ export class BlockSdkCore {
24
24
  * @hidden
25
25
  */
26
26
  // @ts-ignore
27
- static VERSION = "0.0.0-experimental-28533a19d-20251016";
27
+ static VERSION = "0.0.0-experimental-a1a13b445-20251124";
28
28
 
29
29
  /** Storage for this block installation's configuration. */
30
30
 
@@ -98,6 +98,16 @@ export class AbstractMockAirtableInterface extends EventEmitter {
98
98
  setCustomPropertiesAsync(properties) {
99
99
  return Promise.resolve(true);
100
100
  }
101
+ setSelectedSubElementAsync(selectedSubElement) {
102
+ return Promise.resolve(true);
103
+ }
104
+ fetchAndSubscribeToSelectionDataAsync(callback) {
105
+ this.on('selectedSubElementIdUpdates', callback);
106
+ return Promise.resolve({
107
+ selectedSubElementId: null
108
+ });
109
+ }
110
+ unsubscribeFromSelectionData() {}
101
111
  subscribeToModelUpdates(fn) {
102
112
  this.on('modelupdates', fn);
103
113
  }
@@ -1 +1 @@
1
- {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../../src/base/models/record.ts"],"names":[],"mappings":"AAAA,8CAA8C,CAAC,MAAM;AACrD,OAAO,EAAC,KAAK,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAC,UAAU,EAA0B,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAC,KAAK,MAAM,EAAE,KAAK,OAAO,EAAC,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAEH,KAAK,YAAY,EAGpB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,+BAA+B,CAAC;AAC7D,OAAO,wBAAwB,MAAM,+BAA+B,CAAC;AAGrE,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AAEjC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,OAA0B,EAAC,KAAK,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAEpF,QAAA,MAAM,mBAAmB;;;;EAGvB,CAAC;AAOH;;;;;;;GAOG;AACH,KAAK,kBAAkB,GAAG,YAAY,CAAC,OAAO,mBAAmB,CAAC,GAAG,MAAM,CAAC;AAE5E;;;;;;;GAOG;AACH,cAAM,MAAO,SAAQ,UAAU,CAAC,WAAW,EAAE,kBAAkB,CAAC;IAoC5D;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,yBAAyB,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM;IASjF,gBAAgB,CAAC,KAAK,EAAE;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAC,GAAG,OAAO;IAShE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,sCAAsC,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM;IAS3F;;;;;;;OAOG;IACH,cAAc,CAAC,sBAAsB,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,IAAI;IAK5E;;;;;;;OAOG;IACH,iBAAiB,CAAC,sBAAsB,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI;IAOvE;;;;;;;OAOG;IACH,2BAA2B,CACvB,yBAAyB,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,EACnD,IAAI,GAAE,qBAA0B,GACjC,wBAAwB;IAoB3B;;;;;;;;;OASG;IACG,gCAAgC,CAClC,yBAAyB,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,EACnD,IAAI,GAAE,qBAA0B,GACjC,OAAO,CAAC,wBAAwB,CAAC;IAKpC;;;;;;;;OAQG;IACH,IAAI,GAAG,IAAI,MAAM,CAKhB;IACD;;;;;;;;;;;OAWG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;CAsBJ;AAED,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../../src/base/models/record.ts"],"names":[],"mappings":"AAAA,8CAA8C,CAAC,MAAM;AACrD,OAAO,EAAC,KAAK,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EACH,UAAU,EAGb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAC,KAAK,MAAM,EAAE,KAAK,OAAO,EAAC,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAc,KAAK,YAAY,EAAqB,MAAM,4BAA4B,CAAC;AAI9F,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,+BAA+B,CAAC;AAC7D,OAAO,wBAAwB,MAAM,+BAA+B,CAAC;AAGrE,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AAEjC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,OAA0B,EAAC,KAAK,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAEpF,QAAA,MAAM,mBAAmB;;;;EAGvB,CAAC;AAKH;;;;;;;GAOG;AACH,KAAK,kBAAkB,GAAG,YAAY,CAAC,OAAO,mBAAmB,CAAC,GAAG,MAAM,CAAC;AAE5E;;;;;;;GAOG;AACH,cAAM,MAAO,SAAQ,UAAU,CAAC,WAAW,EAAE,kBAAkB,CAAC;IAoC5D;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,yBAAyB,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM;IASjF,gBAAgB,CAAC,KAAK,EAAE;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAC,GAAG,OAAO;IAShE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,sCAAsC,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM;IAS3F;;;;;;;OAOG;IACH,cAAc,CAAC,sBAAsB,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,IAAI;IAK5E;;;;;;;OAOG;IACH,iBAAiB,CAAC,sBAAsB,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI;IAOvE;;;;;;;OAOG;IACH,2BAA2B,CACvB,yBAAyB,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,EACnD,IAAI,GAAE,qBAA0B,GACjC,wBAAwB;IAoB3B;;;;;;;;;OASG;IACG,gCAAgC,CAClC,yBAAyB,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,EACnD,IAAI,GAAE,qBAA0B,GACjC,OAAO,CAAC,wBAAwB,CAAC;IAKpC;;;;;;;;OAQG;IACH,IAAI,GAAG,IAAI,MAAM,CAKhB;IACD;;;;;;;;;;;OAWG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;CAiBJ;AAED,eAAe,MAAM,CAAC"}
@@ -11,6 +11,7 @@ declare const WatchableRecordKeys: Readonly<{
11
11
  * Any key within record that can be watched:
12
12
  * - `'name'`
13
13
  * - `'cellValues'`
14
+ * - `'cellValueInField:' + someFieldId`
14
15
  */
15
16
  type WatchableRecordKey = ObjectValues<typeof WatchableRecordKeys> | string;
16
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../../src/interface/models/record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAC,UAAU,EAA0B,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAC,KAAK,YAAY,EAAC,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAC,KAAK,QAAQ,EAAC,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAC,KAAK,KAAK,EAAC,MAAM,SAAS,CAAC;AAEnC,QAAA,MAAM,mBAAmB;;;EAEvB,CAAC;AACH;;;;GAIG;AACH,KAAK,kBAAkB,GAAG,YAAY,CAAC,OAAO,mBAAmB,CAAC,GAAG,MAAM,CAAC;AAE5E;;;;;;GAMG;AACH,qBAAa,MAAO,SAAQ,UAAU,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;IAIxE;;;;;;;;OAQG;IACH,wBAAwB,CACpB,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC;QACP,OAAO,EAAE,aAAa,CAAC;YAAC,EAAE,EAAE,QAAQ,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC,CAAC;KACxD,CAAC;CAgBL"}
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../../src/interface/models/record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,gBAAgB,CAAC;AAErD,OAAO,EACH,UAAU,EAGb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAc,KAAK,YAAY,EAAC,MAAM,4BAA4B,CAAC;AAE1E,OAAO,EAAC,KAAK,QAAQ,EAAC,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAC,KAAK,KAAK,EAAC,MAAM,SAAS,CAAC;AAEnC,QAAA,MAAM,mBAAmB;;;EAEvB,CAAC;AACH;;;;;GAKG;AACH,KAAK,kBAAkB,GAAG,YAAY,CAAC,OAAO,mBAAmB,CAAC,GAAG,MAAM,CAAC;AAE5E;;;;;;GAMG;AACH,qBAAa,MAAO,SAAQ,UAAU,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;IAWxE;;;;;;;;OAQG;IACH,wBAAwB,CACpB,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC;QACP,OAAO,EAAE,aAAa,CAAC;YAAC,EAAE,EAAE,QAAQ,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC,CAAC;KACxD,CAAC;CAgBL"}
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../../../src/interface/sdk.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAKlD,OAAO,EAEH,KAAK,eAAe,EACvB,MAAM,4BAA4B,CAAC;AAEpC,cAAc;AACd,qBAAa,iBAAkB,SAAQ,YAAY,CAAC,gBAAgB,CAAC;gBACrD,iBAAiB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAsDrE,cAAc;IACd,kBAAkB,IAAI,eAAe;CAYxC"}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../../../src/interface/sdk.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAKlD,OAAO,EAGH,KAAK,eAAe,EACvB,MAAM,4BAA4B,CAAC;AAEpC,cAAc;AACd,qBAAa,iBAAkB,SAAQ,YAAY,CAAC,gBAAgB,CAAC;gBACrD,iBAAiB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAsDrE,cAAc;IACd,kBAAkB,IAAI,eAAe;CAqCxC"}
@@ -57,6 +57,18 @@ export type BlockInstallationPageElementCustomPropertyForAirtableInterface = {
57
57
  type: BlockInstallationPageElementCustomPropertyTypeForAirtableInterface.TABLE_ID;
58
58
  defaultValue?: TableId;
59
59
  });
60
+ /** @hidden */
61
+ export interface SubElementSelectionState {
62
+ subElementId: string;
63
+ sourceLocation?: SourceLocation;
64
+ name?: string;
65
+ }
66
+ /** @hidden */
67
+ interface SourceLocation {
68
+ filePath: string;
69
+ lineNumber: number;
70
+ columnNumber?: number;
71
+ }
60
72
  /**
61
73
  * AirtableInterface is designed as the communication interface between the
62
74
  * Block SDK and Airtable.
@@ -73,5 +85,13 @@ export interface AirtableInterface extends AirtableInterfaceCore<InterfaceSdkMod
73
85
  }>;
74
86
  }>;
75
87
  setCustomPropertiesAsync(properties: Array<BlockInstallationPageElementCustomPropertyForAirtableInterface>): Promise<boolean>;
88
+ setSelectedSubElementAsync(selectedSubElement: SubElementSelectionState | null): Promise<boolean>;
89
+ fetchAndSubscribeToSelectionDataAsync(callback: (data: {
90
+ selectedSubElementId: string | null;
91
+ }) => void): Promise<{
92
+ selectedSubElementId: string | null;
93
+ }>;
94
+ unsubscribeFromSelectionData(): void;
76
95
  }
96
+ export {};
77
97
  //# sourceMappingURL=airtable_interface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"airtable_interface.d.ts","sourceRoot":"","sources":["../../../../../src/interface/types/airtable_interface.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACvB,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAC,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAC,MAAM,8BAA8B,CAAC;AACpG,OAAO,EAAC,KAAK,QAAQ,EAAC,MAAM,QAAQ,CAAC;AAIrC,cAAc;AACd,oBAAY,mBAAmB;IAC3B,+BAA+B,gCAAgC;CAClE;AAED,cAAc;AACd,MAAM,WAAW,8CAA8C;IAC3D,IAAI,EAAE,mBAAmB,CAAC,+BAA+B,CAAC;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB,EAAE,OAAO,CAAC;CACpC;AAED,cAAc;AACd,MAAM,MAAM,eAAe,GAAG,8CAA8C,CAAC;AAE7E,cAAc;AACd,MAAM,WAAW,WAAY,SAAQ,eAAe;IAChD,UAAU,EAAE,eAAe,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;CACtB;AAED,cAAc;AACd,MAAM,WAAW,WAAW;IACxB,gBAAgB,IAAI,MAAM,CAAC;CAC9B;AAID,cAAc;AACd,oBAAY,kEAAkE;IAC1E,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,QAAQ,YAAY;IACpB,QAAQ,YAAY;CACvB;AAID,cAAc;AACd,MAAM,MAAM,8DAA8D,GAAG;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACjB,GAAG,CACE;IACI,IAAI,EAAE,kEAAkE,CAAC,OAAO,CAAC;IACjF,YAAY,EAAE,OAAO,CAAC;CACzB,GACD;IACI,IAAI,EAAE,kEAAkE,CAAC,MAAM,CAAC;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB,GACD;IACI,IAAI,EAAE,kEAAkE,CAAC,IAAI,CAAC;IAC9E,cAAc,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB,GACD;IACI,IAAI,EAAE,kEAAkE,CAAC,QAAQ,CAAC;IAClF,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B,GACD;IACI,IAAI,EAAE,kEAAkE,CAAC,QAAQ,CAAC;IAClF,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B,CACN,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,iBAAkB,SAAQ,qBAAqB,CAAC,gBAAgB,CAAC;IAC9E,WAAW,EAAE,WAAW,CAAC;IAEzB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACtD,wBAAwB,CACpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC;QAAC,OAAO,EAAE,aAAa,CAAC;YAAC,EAAE,EAAE,QAAQ,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC,CAAA;KAAC,CAAC,CAAC;IACnE,wBAAwB,CACpB,UAAU,EAAE,KAAK,CAAC,8DAA8D,CAAC,GAClF,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB"}
1
+ {"version":3,"file":"airtable_interface.d.ts","sourceRoot":"","sources":["../../../../../src/interface/types/airtable_interface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /** @module @airtable/blocks/interface/ui: SelectableWrapper */ /** */
2
+ import React from 'react';
3
+ /** @hidden */
4
+ export interface SelectableWrapperProps {
5
+ /** The child component to wrap with selection functionality */
6
+ children: React.ReactNode;
7
+ /** The name of this selectable element, to be shown in the properties panel */
8
+ name?: string;
9
+ }
10
+ /**
11
+ * A wrapper component that makes its child selectable with a click overlay.
12
+ * When clicked, the child component is marked as selected. If already selected,
13
+ * the overlay becomes click-through. Selected elements display a blue border.
14
+ *
15
+ * @component
16
+ * @hidden
17
+ */
18
+ export declare function SelectableWrapper({ children, sourceLocation, name }: SelectableWrapperProps): React.JSX.Element;
19
+ //# sourceMappingURL=selectable_wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectable_wrapper.d.ts","sourceRoot":"","sources":["../../../../../src/interface/ui/selectable_wrapper.tsx"],"names":[],"mappings":"AAAA,+DAA+D,CAAC,MAAM;AACtE,OAAO,KAAyD,MAAM,OAAO,CAAC;AAc9E,cAAc;AACd,MAAM,WAAW,sBAAsB;IACnC,+DAA+D;IAC/D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAQ1B,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAC,EAAE,sBAAsB,qBAWzF"}
@@ -3,6 +3,7 @@ import '..';
3
3
  export { CellRenderer } from './cell_renderer';
4
4
  export { expandRecord } from './expand_record';
5
5
  export { initializeBlock } from './initialize_block';
6
+ export { SelectableWrapper } from './selectable_wrapper';
6
7
  export { useBase } from './use_base';
7
8
  export { useColorScheme } from '../../shared/ui/use_color_scheme';
8
9
  export { useCustomProperties } from './use_custom_properties';
@@ -1 +1 @@
1
- {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../../../src/interface/ui/ui.ts"],"names":[],"mappings":"AAAA,OAAO,uBAAuB,CAAC;AAI/B,OAAO,IAAI,CAAC;AAEZ,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAC;AACnC,OAAO,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAC,mBAAmB,EAAC,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAC,UAAU,EAAC,MAAM,eAAe,CAAC;AACzC,OAAO,EAAC,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAC,UAAU,EAAC,MAAM,eAAe,CAAC;AACzC,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAC,OAAO,IAAI,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EACH,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACzB,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../../../src/interface/ui/ui.ts"],"names":[],"mappings":"AAAA,OAAO,uBAAuB,CAAC;AAI/B,OAAO,IAAI,CAAC;AAEZ,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,iBAAiB,EAAC,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAC;AACnC,OAAO,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAC,mBAAmB,EAAC,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAC,UAAU,EAAC,MAAM,eAAe,CAAC;AACzC,OAAO,EAAC,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAC,UAAU,EAAC,MAAM,eAAe,CAAC;AACzC,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAC,OAAO,IAAI,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EACH,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACzB,MAAM,8BAA8B,CAAC"}
@@ -6,8 +6,9 @@ export declare const WatchableRecordKeysCore: Readonly<{
6
6
  name: "name";
7
7
  cellValues: "cellValues";
8
8
  }>;
9
+ export declare const WatchableCellValueInFieldKeyPrefix = "cellValueInField:";
9
10
  /** @hidden */
10
- type WatchableRecordKeyCore = ObjectValues<typeof WatchableRecordKeysCore>;
11
+ type WatchableRecordKeyCore = ObjectValues<typeof WatchableRecordKeysCore> | string;
11
12
  /** @hidden */
12
13
  export declare abstract class RecordCore<SdkModeT extends SdkMode, WatchableKeys extends string = WatchableRecordKeyCore> extends AbstractModel<SdkModeT, SdkModeT['RecordDataT'], WatchableRecordKeyCore | WatchableKeys> {
13
14
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"record_core.d.ts","sourceRoot":"","sources":["../../../../../src/shared/models/record_core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,OAAO,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAKH,KAAK,YAAY,EACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAC,KAAK,OAAO,EAAgB,MAAM,oBAAoB,CAAC;AAE/D,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAG7C,eAAO,MAAM,uBAAuB;;;EAKlC,CAAC;AAEH,cAAc;AACd,KAAK,sBAAsB,GAAG,YAAY,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE3E,cAAc;AACd,8BAAsB,UAAU,CAC5B,QAAQ,SAAS,OAAO,EACxB,aAAa,SAAS,MAAM,GAAG,sBAAsB,CACvD,SAAQ,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,sBAAsB,GAAG,aAAa,CAAC;IAyF9F;;;;;;;;;;OAUG;IACH,YAAY,CAAC,yBAAyB,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO;IAoCvF;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,yBAAyB,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM;IAiB9F;;;;;;;;OAQG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IACD;;;;;;;;;OASG;IACH,IAAI,WAAW,IAAI,IAAI,CAEtB;CAmBJ"}
1
+ {"version":3,"file":"record_core.d.ts","sourceRoot":"","sources":["../../../../../src/shared/models/record_core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,OAAO,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAA+C,KAAK,YAAY,EAAC,MAAM,kBAAkB,CAAC;AAEjG,OAAO,EAAC,KAAK,OAAO,EAAgB,MAAM,oBAAoB,CAAC;AAE/D,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAG7C,eAAO,MAAM,uBAAuB;;;EAKlC,CAAC;AAIH,eAAO,MAAM,kCAAkC,sBAAsB,CAAC;AAEtE,cAAc;AACd,KAAK,sBAAsB,GACrB,YAAY,CAAC,OAAO,uBAAuB,CAAC,GAE5C,MAAM,CAAC;AAEb,cAAc;AACd,8BAAsB,UAAU,CAC5B,QAAQ,SAAS,OAAO,EACxB,aAAa,SAAS,MAAM,GAAG,sBAAsB,CACvD,SAAQ,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,sBAAsB,GAAG,aAAa,CAAC;IAqF9F;;;;;;;;;;OAUG;IACH,YAAY,CAAC,yBAAyB,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO;IAoCvF;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,yBAAyB,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM;IAiB9F;;;;;;;;OAQG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IACD;;;;;;;;;OASG;IACH,IAAI,WAAW,IAAI,IAAI,CAEtB;CAuBJ"}
@@ -1,6 +1,6 @@
1
1
  import EventEmitter from 'events';
2
2
  import { type FieldTypeProviderCore, type GlobalConfigHelpers } from '../../shared/types/airtable_interface_core';
3
- import { type AirtableInterface, type SdkInitData, type IdGenerator, type BlockInstallationPageElementCustomPropertyForAirtableInterface } from '../../interface/types/airtable_interface';
3
+ import { type AirtableInterface, type SdkInitData, type IdGenerator, type BlockInstallationPageElementCustomPropertyForAirtableInterface, type SubElementSelectionState } from '../../interface/types/airtable_interface';
4
4
  import { type RecordId } from '../../shared/types/hyper_ids';
5
5
  import { type ModelChange } from '../../shared/types/base_core';
6
6
  import { type PermissionCheckResult } from '../../shared/types/mutations_core';
@@ -37,6 +37,13 @@ export declare abstract class AbstractMockAirtableInterface extends EventEmitter
37
37
  }>;
38
38
  }>;
39
39
  setCustomPropertiesAsync(properties: Array<BlockInstallationPageElementCustomPropertyForAirtableInterface>): Promise<boolean>;
40
+ setSelectedSubElementAsync(selectedSubElement: SubElementSelectionState | null): Promise<boolean>;
41
+ fetchAndSubscribeToSelectionDataAsync(callback: (data: {
42
+ selectedSubElementId: string | null;
43
+ }) => void): Promise<{
44
+ selectedSubElementId: string | null;
45
+ }>;
46
+ unsubscribeFromSelectionData(): void;
40
47
  subscribeToModelUpdates(fn: (...args: any[]) => void): void;
41
48
  subscribeToGlobalConfigUpdates(): void;
42
49
  triggerModelUpdates(changes: ReadonlyArray<ModelChange>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"abstract_mock_airtable_interface.d.ts","sourceRoot":"","sources":["../../../../../src/testing/interface/abstract_mock_airtable_interface.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAGH,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAC3B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,8DAA8D,EACtE,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAe,KAAK,QAAQ,EAAC,MAAM,8BAA8B,CAAC;AAGzE,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAC,KAAK,qBAAqB,EAAC,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAC,KAAK,QAAQ,EAAC,MAAM,iCAAiC,CAAC;AAwD9D;;;;;GAKG;AACH,8BAAsB,6BAClB,SAAQ,YACR,YAAW,iBAAiB;IAE5B,WAAW,EAAG,WAAW,CAAC;IAE1B,OAAO,CAAC,SAAS,CAAc;gBAEnB,QAAQ,EAAE,WAAW;IAMjC;;;;;OAKG;IACH,KAAK;IAKL,IAAI,iBAAiB,0BAEpB;IAED,IAAI,mBAAmB,wBAEtB;IAED,IAAI,WAAW,gBAEd;IAED,8BAA8B;IAE9B,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlF,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,GAAG,qBAAqB;IAMtE,wBAAwB,CACpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC;QAAC,OAAO,EAAE,aAAa,CAAC;YAAC,EAAE,EAAE,QAAQ,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC,CAAA;KAAC,CAAC;IAIlE,wBAAwB,CACpB,UAAU,EAAE,KAAK,CAAC,8DAA8D,CAAC,GAClF,OAAO,CAAC,OAAO,CAAC;IAInB,uBAAuB,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;IAKpD,8BAA8B;IAE9B,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC;IAKvD,0BAA0B;IAE1B,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAC9D,QAAQ,CAAC,WAAW,IAAI,IAAI;IAC5B,QAAQ,CAAC,UAAU,IAAI,IAAI;IAC3B,QAAQ,CAAC,aAAa,IAAI,IAAI;IAC9B,QAAQ,CAAC,QAAQ,IAAI,IAAI;CAC5B"}
1
+ {"version":3,"file":"abstract_mock_airtable_interface.d.ts","sourceRoot":"","sources":["../../../../../src/testing/interface/abstract_mock_airtable_interface.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAGH,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAC3B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,8DAA8D,EACnE,KAAK,wBAAwB,EAChC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAe,KAAK,QAAQ,EAAC,MAAM,8BAA8B,CAAC;AAGzE,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAC,KAAK,qBAAqB,EAAC,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAC,KAAK,QAAQ,EAAC,MAAM,iCAAiC,CAAC;AAwD9D;;;;;GAKG;AACH,8BAAsB,6BAClB,SAAQ,YACR,YAAW,iBAAiB;IAE5B,WAAW,EAAG,WAAW,CAAC;IAE1B,OAAO,CAAC,SAAS,CAAc;gBAEnB,QAAQ,EAAE,WAAW;IAMjC;;;;;OAKG;IACH,KAAK;IAKL,IAAI,iBAAiB,0BAEpB;IAED,IAAI,mBAAmB,wBAEtB;IAED,IAAI,WAAW,gBAEd;IAED,8BAA8B;IAE9B,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlF,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,GAAG,qBAAqB;IAMtE,wBAAwB,CACpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC;QAAC,OAAO,EAAE,aAAa,CAAC;YAAC,EAAE,EAAE,QAAQ,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC,CAAA;KAAC,CAAC;IAIlE,wBAAwB,CACpB,UAAU,EAAE,KAAK,CAAC,8DAA8D,CAAC,GAClF,OAAO,CAAC,OAAO,CAAC;IAInB,0BAA0B,CACtB,kBAAkB,EAAE,wBAAwB,GAAG,IAAI,GACpD,OAAO,CAAC,OAAO,CAAC;IAInB,qCAAqC,CACjC,QAAQ,EAAE,CAAC,IAAI,EAAE;QAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;KAAC,KAAK,IAAI,GAChE,OAAO,CAAC;QACP,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;KACvC,CAAC;IAKF,4BAA4B,IAAI,IAAI;IAEpC,uBAAuB,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;IAKpD,8BAA8B;IAE9B,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC;IAKvD,0BAA0B;IAE1B,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAC9D,QAAQ,CAAC,WAAW,IAAI,IAAI;IAC5B,QAAQ,CAAC,UAAU,IAAI,IAAI;IAC3B,QAAQ,CAAC,aAAa,IAAI,IAAI;IAC9B,QAAQ,CAAC,QAAQ,IAAI,IAAI;CAC5B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@airtable/blocks",
3
- "version": "0.0.0-experimental-28533a19d-20251016",
3
+ "version": "0.0.0-experimental-a1a13b445-20251124",
4
4
  "description": "Airtable Blocks SDK",
5
5
  "type": "module",
6
6
  "repository": {