@atlaskit/top-layer 0.1.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/cjs/arrow/index.js +1 -1
  3. package/dist/cjs/internal/anchor-positioning-fallback.js +82 -22
  4. package/dist/cjs/internal/resolve-css-length-to-pixels.js +53 -0
  5. package/dist/cjs/internal/resolve-css-length.js +18 -0
  6. package/dist/cjs/internal/resolve-placement.js +47 -6
  7. package/dist/cjs/internal/use-anchor-positioning.js +180 -36
  8. package/dist/cjs/placement-map/index.js +31 -3
  9. package/dist/cjs/popup/popup-content.js +0 -2
  10. package/dist/cjs/testing/polyfill.js +347 -0
  11. package/dist/cjs/testing/to-be-visible.js +92 -0
  12. package/dist/es2019/arrow/index.js +22 -3
  13. package/dist/es2019/internal/anchor-positioning-fallback.js +80 -17
  14. package/dist/es2019/internal/resolve-css-length-to-pixels.js +48 -0
  15. package/dist/es2019/internal/resolve-css-length.js +13 -0
  16. package/dist/es2019/internal/resolve-placement.js +48 -6
  17. package/dist/es2019/internal/use-anchor-positioning.js +173 -28
  18. package/dist/es2019/placement-map/index.js +25 -3
  19. package/dist/es2019/popup/popup-content.js +0 -2
  20. package/dist/es2019/testing/polyfill.js +351 -0
  21. package/dist/es2019/testing/to-be-visible.js +85 -0
  22. package/dist/esm/arrow/index.js +1 -1
  23. package/dist/esm/internal/anchor-positioning-fallback.js +82 -22
  24. package/dist/esm/internal/resolve-css-length-to-pixels.js +47 -0
  25. package/dist/esm/internal/resolve-css-length.js +12 -0
  26. package/dist/esm/internal/resolve-placement.js +48 -6
  27. package/dist/esm/internal/use-anchor-positioning.js +179 -36
  28. package/dist/esm/placement-map/index.js +30 -3
  29. package/dist/esm/popup/popup-content.js +0 -2
  30. package/dist/esm/testing/polyfill.js +345 -0
  31. package/dist/esm/testing/to-be-visible.js +89 -0
  32. package/dist/types/internal/anchor-positioning-fallback.d.ts +11 -9
  33. package/dist/types/internal/resolve-css-length-to-pixels.d.ts +22 -0
  34. package/dist/types/internal/resolve-css-length.d.ts +8 -0
  35. package/dist/types/internal/resolve-placement.d.ts +47 -5
  36. package/dist/types/internal/use-anchor-positioning.d.ts +18 -7
  37. package/dist/types/placement-map/index.d.ts +11 -5
  38. package/dist/types/popup/types.d.ts +15 -30
  39. package/dist/types/testing/polyfill.d.ts +48 -0
  40. package/dist/types/testing/to-be-visible.d.ts +23 -0
  41. package/dist/types-ts4.5/internal/anchor-positioning-fallback.d.ts +11 -9
  42. package/dist/types-ts4.5/internal/resolve-css-length-to-pixels.d.ts +22 -0
  43. package/dist/types-ts4.5/internal/resolve-css-length.d.ts +8 -0
  44. package/dist/types-ts4.5/internal/resolve-placement.d.ts +47 -5
  45. package/dist/types-ts4.5/internal/use-anchor-positioning.d.ts +18 -7
  46. package/dist/types-ts4.5/placement-map/index.d.ts +14 -5
  47. package/dist/types-ts4.5/popup/types.d.ts +15 -30
  48. package/dist/types-ts4.5/testing/polyfill.d.ts +48 -0
  49. package/dist/types-ts4.5/testing/to-be-visible.d.ts +23 -0
  50. package/package.json +3 -2
  51. package/testing/polyfill/package.json +17 -0
  52. package/testing/to-be-visible/package.json +17 -0
@@ -0,0 +1,347 @@
1
+ "use strict";
2
+
3
+ /* eslint-disable compat/compat */
4
+ /**
5
+ * Popover API & HTMLDialogElement polyfills for jsdom.
6
+ *
7
+ * jsdom does not implement the Popover API or the HTMLDialogElement methods
8
+ * (showModal, show, close). This polyfill provides faithful implementations,
9
+ * including timing semantics validated against Chromium via Playwright.
10
+ *
11
+ * Behaviour:
12
+ * - beforetoggle: sync, cancelable on show only. toggle: async task, not cancelable.
13
+ * - Rapid show/hide coalesces into one toggle event (originalOldState to finalNewState).
14
+ * - Dialog: showModal/show fire beforetoggle+toggle. close fires toggle then close event.
15
+ * - Popover open state tracked via `data-popover-open` (no `:popover-open` in jsdom).
16
+ *
17
+ * Companion `toBeVisible` patch lives at `./to-be-visible`.
18
+ *
19
+ * Importing this module has the side-effect of patching the relevant
20
+ * prototypes. It is safe to import multiple times; each branch is guarded
21
+ * to avoid overwriting native implementations or re-patching.
22
+ */
23
+
24
+ /**
25
+ * e.g. `<div#my-id.class-a.class-b>`
26
+ */
27
+ function describeElement(_ref) {
28
+ var element = _ref.element;
29
+ var tag = element.tagName ? element.tagName.toLowerCase() : 'unknown';
30
+ var id = element.id ? "#".concat(element.id) : '';
31
+ var classes = element.classList && element.classList.length > 0 ? ".".concat(Array.from(element.classList).join('.')) : '';
32
+ return "<".concat(tag).concat(id).concat(classes, ">");
33
+ }
34
+ function createToggleEvent(_ref2) {
35
+ var type = _ref2.type,
36
+ oldState = _ref2.oldState,
37
+ newState = _ref2.newState,
38
+ cancelable = _ref2.cancelable;
39
+ if (typeof globalThis.ToggleEvent === 'function') {
40
+ // ToggleEvent is not in lib.dom.d.ts at the time of writing; cast to any for construction.
41
+ var ToggleEventCtor = globalThis.ToggleEvent;
42
+ return new ToggleEventCtor(type, {
43
+ oldState: oldState,
44
+ newState: newState,
45
+ cancelable: cancelable,
46
+ bubbles: false
47
+ });
48
+ }
49
+ var event = new Event(type, {
50
+ cancelable: cancelable,
51
+ bubbles: false
52
+ });
53
+ event.oldState = oldState;
54
+ event.newState = newState;
55
+ return event;
56
+ }
57
+ function fireToggleEvent(_ref3) {
58
+ var element = _ref3.element,
59
+ type = _ref3.type,
60
+ oldState = _ref3.oldState,
61
+ newState = _ref3.newState,
62
+ cancelable = _ref3.cancelable;
63
+ return element.dispatchEvent(createToggleEvent({
64
+ type: type,
65
+ oldState: oldState,
66
+ newState: newState,
67
+ cancelable: cancelable
68
+ }));
69
+ }
70
+ function oppositeState(_ref4) {
71
+ var state = _ref4.state;
72
+ if (state === 'open') {
73
+ return 'closed';
74
+ }
75
+ return 'open';
76
+ }
77
+
78
+ // Coalesces rapid show/hide into one toggle event per element.
79
+ // Uses setTimeout (task) not Promise.resolve (microtask) to match browser timing.
80
+ function createToggleScheduler() {
81
+ var pending = new Map();
82
+ return function schedule(_ref5) {
83
+ var element = _ref5.element,
84
+ newState = _ref5.newState;
85
+ var existing = pending.get(element);
86
+ if (existing) {
87
+ // Coalesce: keep the original oldState, update newState
88
+ pending.set(element, {
89
+ oldState: existing.oldState,
90
+ newState: newState
91
+ });
92
+ return;
93
+ }
94
+ pending.set(element, {
95
+ oldState: oppositeState({
96
+ state: newState
97
+ }),
98
+ newState: newState
99
+ });
100
+
101
+ // Task queue (setTimeout) — browser fires toggle after microtasks drain, not during
102
+ setTimeout(function () {
103
+ var entry = pending.get(element);
104
+ if (!entry) {
105
+ return;
106
+ }
107
+ pending.delete(element);
108
+ fireToggleEvent({
109
+ element: element,
110
+ type: 'toggle',
111
+ oldState: entry.oldState,
112
+ newState: entry.newState,
113
+ cancelable: false
114
+ });
115
+ }, 0);
116
+ };
117
+ }
118
+
119
+ // Like createToggleScheduler but also fires a close event as a separate task after toggle.
120
+ function createDialogToggleScheduler() {
121
+ var pending = new Map();
122
+ return function schedule(_ref6) {
123
+ var dialog = _ref6.dialog,
124
+ newState = _ref6.newState,
125
+ shouldFireCloseEvent = _ref6.shouldFireCloseEvent;
126
+ var existing = pending.get(dialog);
127
+ if (existing) {
128
+ // Coalesce: keep the original oldState, merge shouldFireCloseEvent
129
+ pending.set(dialog, {
130
+ oldState: existing.oldState,
131
+ newState: newState,
132
+ shouldFireCloseEvent: existing.shouldFireCloseEvent || shouldFireCloseEvent
133
+ });
134
+ return;
135
+ }
136
+ pending.set(dialog, {
137
+ oldState: oppositeState({
138
+ state: newState
139
+ }),
140
+ newState: newState,
141
+ shouldFireCloseEvent: shouldFireCloseEvent
142
+ });
143
+
144
+ // Browser fires toggle as a task, not synchronously or as a microtask
145
+ setTimeout(function () {
146
+ var entry = pending.get(dialog);
147
+ if (!entry) {
148
+ return;
149
+ }
150
+ pending.delete(dialog);
151
+ fireToggleEvent({
152
+ element: dialog,
153
+ type: 'toggle',
154
+ oldState: entry.oldState,
155
+ newState: entry.newState,
156
+ cancelable: false
157
+ });
158
+ if (entry.shouldFireCloseEvent) {
159
+ // Browser fires close as a separate task after toggle
160
+ setTimeout(function () {
161
+ dialog.dispatchEvent(new Event('close', {
162
+ bubbles: false,
163
+ cancelable: false
164
+ }));
165
+ }, 0);
166
+ }
167
+ }, 0);
168
+ };
169
+ }
170
+
171
+ // ─── Popover API ────────────────────────────────────────────────────────────
172
+
173
+ if (typeof HTMLElement !== 'undefined' && !HTMLElement.prototype.showPopover) {
174
+ var schedulePopoverToggle = createToggleScheduler();
175
+ HTMLElement.prototype.showPopover = function showPopover() {
176
+ if (!this.hasAttribute('popover')) {
177
+ throw new DOMException("Failed to execute 'showPopover' on 'HTMLElement': ".concat(describeElement({
178
+ element: this
179
+ }), " is not a popover element. Ensure the element has a 'popover' attribute (e.g. <div popover>)."), 'NotSupportedError');
180
+ }
181
+ if (!this.isConnected) {
182
+ throw new DOMException("Failed to execute 'showPopover' on 'HTMLElement': ".concat(describeElement({
183
+ element: this
184
+ }), " is not connected to the document. Ensure the element has been added to the DOM (e.g. via render() or document.body.appendChild()) before calling showPopover()."), 'InvalidStateError');
185
+ }
186
+ if (this.hasAttribute('data-popover-open')) {
187
+ return; // already showing — no-op
188
+ }
189
+
190
+ // sync, cancelable on show only
191
+ var allowed = fireToggleEvent({
192
+ element: this,
193
+ type: 'beforetoggle',
194
+ oldState: 'closed',
195
+ newState: 'open',
196
+ cancelable: true
197
+ });
198
+ if (!allowed) {
199
+ return;
200
+ }
201
+ this.setAttribute('data-popover-open', '');
202
+ schedulePopoverToggle({
203
+ element: this,
204
+ newState: 'open'
205
+ });
206
+ };
207
+ HTMLElement.prototype.hidePopover = function hidePopover() {
208
+ if (!this.hasAttribute('popover')) {
209
+ throw new DOMException("Failed to execute 'hidePopover' on 'HTMLElement': ".concat(describeElement({
210
+ element: this
211
+ }), " is not a popover element. Ensure the element has a 'popover' attribute (e.g. <div popover>)."), 'NotSupportedError');
212
+ }
213
+ // Browser does not throw for disconnected elements on hide — just no-op
214
+ if (!this.isConnected || !this.hasAttribute('data-popover-open')) {
215
+ return;
216
+ }
217
+
218
+ // not cancelable on hide
219
+ fireToggleEvent({
220
+ element: this,
221
+ type: 'beforetoggle',
222
+ oldState: 'open',
223
+ newState: 'closed',
224
+ cancelable: false
225
+ });
226
+ this.removeAttribute('data-popover-open');
227
+ schedulePopoverToggle({
228
+ element: this,
229
+ newState: 'closed'
230
+ });
231
+ };
232
+ HTMLElement.prototype.togglePopover = function togglePopover(force) {
233
+ var isOpen = this.hasAttribute('data-popover-open');
234
+ if (typeof force === 'boolean') {
235
+ if (force && !isOpen) {
236
+ this.showPopover();
237
+ } else if (!force && isOpen) {
238
+ this.hidePopover();
239
+ }
240
+ return force;
241
+ }
242
+ if (isOpen) {
243
+ this.hidePopover();
244
+ return false;
245
+ }
246
+ this.showPopover();
247
+ return true;
248
+ };
249
+ }
250
+
251
+ // ─── HTMLDialogElement ──────────────────────────────────────────────────────
252
+
253
+ if (typeof HTMLDialogElement !== 'undefined') {
254
+ var proto = HTMLDialogElement.prototype;
255
+ var scheduleDialogToggle = createDialogToggleScheduler();
256
+ if (typeof proto.showModal !== 'function') {
257
+ proto.showModal = function showModal() {
258
+ if (!this.isConnected) {
259
+ throw new DOMException("Failed to execute 'showModal' on 'HTMLDialogElement': ".concat(describeElement({
260
+ element: this
261
+ }), " is not connected to the document. Ensure the element has been added to the DOM (e.g. via render() or document.body.appendChild()) before calling showModal()."), 'InvalidStateError');
262
+ }
263
+ if (this.hasAttribute('open')) {
264
+ if (this._isModal) {
265
+ return; // already modal — no-op
266
+ }
267
+ throw new DOMException("Failed to execute 'showModal' on 'HTMLDialogElement': ".concat(describeElement({
268
+ element: this
269
+ }), " already has an 'open' attribute, and therefore cannot be opened modally. The dialog was likely opened non-modally with .show(). Call .close() first, then .showModal()."), 'InvalidStateError');
270
+ }
271
+ fireToggleEvent({
272
+ element: this,
273
+ type: 'beforetoggle',
274
+ oldState: 'closed',
275
+ newState: 'open',
276
+ cancelable: false
277
+ });
278
+ this.setAttribute('open', '');
279
+ this._isModal = true;
280
+ scheduleDialogToggle({
281
+ dialog: this,
282
+ newState: 'open',
283
+ shouldFireCloseEvent: false
284
+ });
285
+ };
286
+ }
287
+ if (typeof proto.show !== 'function') {
288
+ proto.show = function show() {
289
+ // Browser does not throw for disconnected elements on show — just no-op
290
+ if (!this.isConnected || this.hasAttribute('open')) {
291
+ return;
292
+ }
293
+ fireToggleEvent({
294
+ element: this,
295
+ type: 'beforetoggle',
296
+ oldState: 'closed',
297
+ newState: 'open',
298
+ cancelable: false
299
+ });
300
+ this.setAttribute('open', '');
301
+ this._isModal = false;
302
+ scheduleDialogToggle({
303
+ dialog: this,
304
+ newState: 'open',
305
+ shouldFireCloseEvent: false
306
+ });
307
+ };
308
+ }
309
+ if (typeof proto.close !== 'function') {
310
+ proto.close = function close(returnValue) {
311
+ if (!this.hasAttribute('open')) {
312
+ return; // already closed — no-op
313
+ }
314
+
315
+ // Sync beforetoggle (not cancelable) — matches browser behavior
316
+ fireToggleEvent({
317
+ element: this,
318
+ type: 'beforetoggle',
319
+ oldState: 'open',
320
+ newState: 'closed',
321
+ cancelable: false
322
+ });
323
+ this.removeAttribute('open');
324
+ this._isModal = false;
325
+ if (returnValue !== undefined) {
326
+ this.returnValue = returnValue;
327
+ }
328
+ scheduleDialogToggle({
329
+ dialog: this,
330
+ newState: 'closed',
331
+ shouldFireCloseEvent: true
332
+ });
333
+ };
334
+ }
335
+ if (!('returnValue' in proto)) {
336
+ Object.defineProperty(proto, 'returnValue', {
337
+ get: function get() {
338
+ return this._returnValue === undefined ? '' : this._returnValue;
339
+ },
340
+ set: function set(value) {
341
+ this._returnValue = String(value);
342
+ },
343
+ configurable: true,
344
+ enumerable: true
345
+ });
346
+ }
347
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+
3
+ var _matchers = require("@testing-library/jest-dom/matchers");
4
+ /* eslint-disable compat/compat */
5
+ /* global expect */
6
+ /**
7
+ * Patches `toBeVisible()` to understand popover and dialog visibility.
8
+ *
9
+ * jest-dom's `toBeVisible()` does not know about the Popover API. In real
10
+ * browsers the UA stylesheet hides `[popover]` with `display: none`, but
11
+ * jsdom has no such stylesheet — so closed popovers incorrectly appear visible.
12
+ *
13
+ * Raw jest-dom results in jsdom:
14
+ *
15
+ * closed popover / child → true (WRONG — should be false)
16
+ * open popover / child → true (correct)
17
+ * closed dialog / child → false (correct — jsdom natively hides <dialog>)
18
+ * open dialog / child → true (correct)
19
+ *
20
+ * We correct both false positives and false negatives:
21
+ * 1. Delegate to the original first.
22
+ * 2. If it says "visible" → check for closed top-layer hosts (false positive).
23
+ * 3. If it says "not visible" → check for open top-layer hosts (false negative).
24
+ *
25
+ * Must load via `setupFilesAfterEnv` (after jest-dom registers its matchers).
26
+ * Polyfills live in `./polyfill` (loaded via `setupFiles`).
27
+ */
28
+
29
+ // Delegating to jest-dom's matcher; types come from @testing-library/jest-dom.
30
+ // eslint-disable-next-line import/no-extraneous-dependencies
31
+
32
+ /**
33
+ * Finds the nearest popover or dialog ancestor (including the element itself)
34
+ * and returns its state: 'open', 'closed', or null if no top-layer ancestor exists.
35
+ *
36
+ * Checking the *nearest* ancestor handles nesting correctly:
37
+ * a closed popover inside an open popover → nearest is closed → not visible.
38
+ */
39
+ function nearestTopLayerState(element) {
40
+ if (!element) {
41
+ return null;
42
+ }
43
+ if (element.hasAttribute('popover')) {
44
+ return element.hasAttribute('data-popover-open') ? 'open' : 'closed';
45
+ }
46
+ if (element.nodeName === 'DIALOG') {
47
+ return element.hasAttribute('open') ? 'open' : 'closed';
48
+ }
49
+ return nearestTopLayerState(element.parentElement);
50
+ }
51
+ function getNearestTopLayerType(element) {
52
+ if (!element.closest) {
53
+ return 'top-layer element';
54
+ }
55
+ if (element.closest('[popover]')) {
56
+ return 'popover';
57
+ }
58
+ return 'dialog';
59
+ }
60
+
61
+ // `expect` is registered globally by jest before this file runs.
62
+
63
+ expect.extend({
64
+ toBeVisible: function toBeVisible(element) {
65
+ var originalResult = _matchers.toBeVisible.call(this, element);
66
+ var topLayerState = nearestTopLayerState(element);
67
+ if (originalResult.pass) {
68
+ // Original says visible — override if nearest top-layer host is closed.
69
+ if (topLayerState === 'closed') {
70
+ return {
71
+ pass: false,
72
+ message: function message() {
73
+ return "expected element to be visible, but it is inside a closed ".concat(getNearestTopLayerType(element));
74
+ }
75
+ };
76
+ }
77
+ return originalResult;
78
+ }
79
+
80
+ // Original says not visible — override if nearest top-layer host is open.
81
+ // jsdom may hide [popover] elements even when they are logically open.
82
+ if (topLayerState === 'open') {
83
+ return {
84
+ pass: true,
85
+ message: function message() {
86
+ return "expected element not to be visible, but it is inside an open ".concat(getNearestTopLayerType(element));
87
+ }
88
+ };
89
+ }
90
+ return originalResult;
91
+ }
92
+ });
@@ -79,70 +79,89 @@ const ARROW_CSS = `
79
79
  * inline-end (right of anchor) → margin-inline-start (left, facing anchor)
80
80
  */
81
81
 
82
- /* Single-axis centered */
82
+ /* Each rule sets two margins: the anchor-facing margin for the gap
83
+ (via --ds-arrow-size) and one cross-axis margin for the shift
84
+ (via one of --ds-cross-axis-shift-margin-start, --ds-cross-axis-shift-margin-end,
85
+ --ds-cross-axis-shift-margin-block-start, or --ds-cross-axis-shift-margin-block-end). The
86
+ side matches the popover's anchored cross-axis edge per align. Only
87
+ one of the four properties is non-zero at a time; useAnchorPosition
88
+ picks it. See notes/architecture/positioning.md for details. */
89
+ /* Single-axis centered (align: center) */
83
90
  @position-try --ds-arrow-block-start {
84
91
  position-area: block-start;
85
92
  margin: 0;
86
93
  margin-block-end: var(--ds-arrow-size, 8px);
94
+ margin-inline-start: var(--ds-cross-axis-shift-margin-start, 0px);
87
95
  }
88
96
  @position-try --ds-arrow-block-end {
89
97
  position-area: block-end;
90
98
  margin: 0;
91
99
  margin-block-start: var(--ds-arrow-size, 8px);
100
+ margin-inline-start: var(--ds-cross-axis-shift-margin-start, 0px);
92
101
  }
93
102
  @position-try --ds-arrow-inline-start {
94
103
  position-area: inline-start;
95
104
  margin: 0;
96
105
  margin-inline-end: var(--ds-arrow-size, 8px);
106
+ margin-block-start: var(--ds-cross-axis-shift-margin-block-start, 0px);
97
107
  }
98
108
  @position-try --ds-arrow-inline-end {
99
109
  position-area: inline-end;
100
110
  margin: 0;
101
111
  margin-inline-start: var(--ds-arrow-size, 8px);
112
+ margin-block-start: var(--ds-cross-axis-shift-margin-block-start, 0px);
102
113
  }
103
114
 
104
- /* Block edge + inline span */
115
+ /* Block edge + inline span (align: start uses span-inline-end; align: end uses span-inline-start) */
105
116
  @position-try --ds-arrow-block-start-span-inline-start {
106
117
  position-area: block-start span-inline-start;
107
118
  margin: 0;
108
119
  margin-block-end: var(--ds-arrow-size, 8px);
120
+ margin-inline-end: var(--ds-cross-axis-shift-margin-end, 0px);
109
121
  }
110
122
  @position-try --ds-arrow-block-start-span-inline-end {
111
123
  position-area: block-start span-inline-end;
112
124
  margin: 0;
113
125
  margin-block-end: var(--ds-arrow-size, 8px);
126
+ margin-inline-start: var(--ds-cross-axis-shift-margin-start, 0px);
114
127
  }
115
128
  @position-try --ds-arrow-block-end-span-inline-start {
116
129
  position-area: block-end span-inline-start;
117
130
  margin: 0;
118
131
  margin-block-start: var(--ds-arrow-size, 8px);
132
+ margin-inline-end: var(--ds-cross-axis-shift-margin-end, 0px);
119
133
  }
120
134
  @position-try --ds-arrow-block-end-span-inline-end {
121
135
  position-area: block-end span-inline-end;
122
136
  margin: 0;
123
137
  margin-block-start: var(--ds-arrow-size, 8px);
138
+ margin-inline-start: var(--ds-cross-axis-shift-margin-start, 0px);
124
139
  }
125
140
 
126
- /* Inline edge + block span */
141
+ /* Inline edge + block span (align: start uses span-block-end; align: end uses span-block-start) */
127
142
  @position-try --ds-arrow-inline-start-span-block-start {
128
143
  position-area: inline-start span-block-start;
129
144
  margin: 0;
130
145
  margin-inline-end: var(--ds-arrow-size, 8px);
146
+ margin-block-end: var(--ds-cross-axis-shift-margin-block-end, 0px);
131
147
  }
132
148
  @position-try --ds-arrow-inline-start-span-block-end {
133
149
  position-area: inline-start span-block-end;
134
150
  margin: 0;
135
151
  margin-inline-end: var(--ds-arrow-size, 8px);
152
+ margin-block-start: var(--ds-cross-axis-shift-margin-block-start, 0px);
136
153
  }
137
154
  @position-try --ds-arrow-inline-end-span-block-start {
138
155
  position-area: inline-end span-block-start;
139
156
  margin: 0;
140
157
  margin-inline-start: var(--ds-arrow-size, 8px);
158
+ margin-block-end: var(--ds-cross-axis-shift-margin-block-end, 0px);
141
159
  }
142
160
  @position-try --ds-arrow-inline-end-span-block-end {
143
161
  position-area: inline-end span-block-end;
144
162
  margin: 0;
145
163
  margin-inline-start: var(--ds-arrow-size, 8px);
164
+ margin-block-start: var(--ds-cross-axis-shift-margin-block-start, 0px);
146
165
  }
147
166
  `;
148
167