@fusion.dev/helix-headless 0.32.0 → 0.33.1

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 (61) hide show
  1. package/custom-elements.json +876 -164
  2. package/dist/area-chart/root/area-chart-root.d.ts +8 -0
  3. package/dist/area-chart/root/area-chart-root.js +1 -0
  4. package/dist/bar-chart/root/bar-chart-root.d.ts +8 -0
  5. package/dist/bar-chart/root/bar-chart-root.js +2 -1
  6. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +1 -1
  7. package/dist/carousel/root/carousel-root.d.ts +12 -0
  8. package/dist/carousel/root/carousel-root.js +11 -7
  9. package/dist/chat/composer/chat-composer.d.ts +4 -0
  10. package/dist/chat/root/chat-root.d.ts +17 -0
  11. package/dist/chat/root/chat-root.js +12 -1
  12. package/dist/code-block/root/code-block-root.d.ts +25 -3
  13. package/dist/code-block/root/code-block-root.js +16 -5
  14. package/dist/color-picker/root/color-picker-root.js +2 -1
  15. package/dist/copy-button/root/copy-button-root.d.ts +8 -0
  16. package/dist/copy-button/root/copy-button-root.js +4 -1
  17. package/dist/data-table/root/data-table-root.d.ts +22 -3
  18. package/dist/data-table/root/data-table-root.js +25 -16
  19. package/dist/date-input/root/date-input-root.d.ts +34 -1
  20. package/dist/date-input/root/date-input-root.js +27 -1
  21. package/dist/date-picker/root/date-picker-root.js +6 -8
  22. package/dist/donut-chart/root/donut-chart-root.d.ts +21 -5
  23. package/dist/donut-chart/root/donut-chart-root.js +18 -6
  24. package/dist/drilldown/item/drilldown-item.js +1 -1
  25. package/dist/drilldown/root/drilldown-root.js +5 -4
  26. package/dist/heatmap/root/heatmap-root.d.ts +11 -2
  27. package/dist/icon/root/icon-root.d.ts +8 -0
  28. package/dist/icon/root/icon-root.js +5 -0
  29. package/dist/line-chart/root/line-chart-root.d.ts +9 -1
  30. package/dist/line-chart/root/line-chart-root.js +1 -0
  31. package/dist/menu/item/menu-item.js +1 -1
  32. package/dist/menu/root/menu-root.js +5 -4
  33. package/dist/object-inspector/root/object-inspector-root.d.ts +8 -0
  34. package/dist/object-inspector/root/object-inspector-root.js +20 -15
  35. package/dist/pagination/root/pagination-root.js +1 -1
  36. package/dist/pin-input/root/pin-input-root.d.ts +7 -1
  37. package/dist/pin-input/root/pin-input-root.js +5 -7
  38. package/dist/scatter-chart/root/scatter-chart-root.d.ts +20 -0
  39. package/dist/scatter-chart/root/scatter-chart-root.js +15 -9
  40. package/dist/scroll-area/root/scroll-area-root.js +3 -2
  41. package/dist/sparkline/root/sparkline-root.js +1 -0
  42. package/dist/splitter/root/splitter-root.d.ts +11 -0
  43. package/dist/splitter/root/splitter-root.js +16 -16
  44. package/dist/table/cell/table-cell.d.ts +2 -0
  45. package/dist/table/column/table-column.d.ts +40 -6
  46. package/dist/table/column/table-column.js +23 -3
  47. package/dist/table/root/table-root.d.ts +76 -11
  48. package/dist/table/root/table-root.js +90 -3
  49. package/dist/table/row/table-row.d.ts +14 -0
  50. package/dist/table/row/table-row.js +16 -0
  51. package/dist/toolbar/root/toolbar-root.js +6 -5
  52. package/dist/tooltip/root/tooltip-root.d.ts +20 -0
  53. package/dist/tooltip/root/tooltip-root.js +21 -3
  54. package/dist/tour/root/tour-root.js +1 -1
  55. package/dist/tour/stop/tour-stop.d.ts +10 -0
  56. package/dist/tour/stop/tour-stop.js +9 -2
  57. package/dist/tree/root/tree-root.js +4 -3
  58. package/dist/video/root/video-root.js +7 -0
  59. package/package.json +5 -5
  60. package/types/jsx.d.ts +1506 -596
  61. package/types/vue.d.ts +55 -23
@@ -75,9 +75,17 @@ declare const HelixHeadlessAreaChart_base: typeof HelixElement & (new (...args:
75
75
  * @csspart tooltip - The bubble, forwarded from `Tooltip`.
76
76
  * @csspart tooltip-anchor - The `Tooltip` element itself.
77
77
  * @csspart tooltip-arrow - The bubble's point, forwarded from `Tooltip`.
78
+ * @csspart tooltip-arrow-bottom - The point while the bubble is below the reading, so on its top edge, beside `tooltip-arrow`.
79
+ * @csspart tooltip-arrow-left - The point while the bubble is left of the reading, so on its right edge, beside `tooltip-arrow`.
80
+ * @csspart tooltip-arrow-right - The point while the bubble is right of the reading, so on its left edge, beside `tooltip-arrow`.
81
+ * @csspart tooltip-arrow-top - The point while the bubble is above the reading, so on its bottom edge, beside `tooltip-arrow`.
82
+ * @csspart tooltip-bottom - The bubble while it is below the reading, beside `tooltip`.
78
83
  * @csspart tooltip-cell - One column's name and value inside the tooltip.
79
84
  * @csspart tooltip-label - The reading's own name inside the tooltip.
85
+ * @csspart tooltip-left - The bubble while it is left of the reading, beside `tooltip`.
80
86
  * @csspart tooltip-name - A column's name inside the tooltip.
87
+ * @csspart tooltip-right - The bubble while it is right of the reading, beside `tooltip`.
88
+ * @csspart tooltip-top - The bubble while it is above the reading, beside `tooltip`.
81
89
  * @csspart tooltip-value - A column's value inside the tooltip.
82
90
  */
83
91
  export declare class HelixHeadlessAreaChart extends HelixHeadlessAreaChart_base {
@@ -84,6 +84,7 @@ let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSour
84
84
  const order = stack.layers.map((_, depth) => depth).reverse();
85
85
  return html `<div aria-hidden="true" id="helix-chart-plot" part="plot">
86
86
  <svg part="svg"
87
+ data-mirror
87
88
  preserveAspectRatio="none"
88
89
  viewBox="0 0 ${WIDTH} ${HEIGHT}"
89
90
  xmlns="http://www.w3.org/2000/svg"
@@ -52,9 +52,17 @@ declare const HelixHeadlessBarChart_base: typeof HelixElement & (new (...args: a
52
52
  * @csspart tooltip - The bubble, forwarded from `Tooltip`.
53
53
  * @csspart tooltip-anchor - The `Tooltip` element itself.
54
54
  * @csspart tooltip-arrow - The bubble's point, forwarded from `Tooltip`.
55
+ * @csspart tooltip-arrow-bottom - The point while the bubble is below the reading, so on its top edge, beside `tooltip-arrow`.
56
+ * @csspart tooltip-arrow-left - The point while the bubble is left of the reading, so on its right edge, beside `tooltip-arrow`.
57
+ * @csspart tooltip-arrow-right - The point while the bubble is right of the reading, so on its left edge, beside `tooltip-arrow`.
58
+ * @csspart tooltip-arrow-top - The point while the bubble is above the reading, so on its bottom edge, beside `tooltip-arrow`.
59
+ * @csspart tooltip-bottom - The bubble while it is below the reading, beside `tooltip`.
55
60
  * @csspart tooltip-cell - One column's name and value inside the tooltip.
56
61
  * @csspart tooltip-label - The reading's own name inside the tooltip.
62
+ * @csspart tooltip-left - The bubble while it is left of the reading, beside `tooltip`.
57
63
  * @csspart tooltip-name - A column's name inside the tooltip.
64
+ * @csspart tooltip-right - The bubble while it is right of the reading, beside `tooltip`.
65
+ * @csspart tooltip-top - The bubble while it is above the reading, beside `tooltip`.
58
66
  * @csspart tooltip-value - A column's value inside the tooltip.
59
67
  *
60
68
  * @cssproperty --bar-chart-axis - The color of a single-series axis, taken from that series.
@@ -107,6 +107,7 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource
107
107
  part="plot"
108
108
  >
109
109
  <svg part="svg"
110
+ data-mirror
110
111
  preserveAspectRatio="none"
111
112
  viewBox="0 0 100 ${HEIGHT}"
112
113
  xmlns="http://www.w3.org/2000/svg"
@@ -219,7 +220,7 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource
219
220
  const slot = 100 / this.readings;
220
221
  const across = at * slot + slot / 2;
221
222
  return drawTooltip(this.sourceRows, at, this.tag('tooltip'), {
222
- placement: sideways ? 'right' : 'top',
223
+ placement: sideways ? (this.pointer.mirrored ? 'left' : 'right') : 'top',
223
224
  x: sideways ? `${far}%` : `${across}%`,
224
225
  y: sideways ? `${across}%` : `${far}%`,
225
226
  });
@@ -23,7 +23,7 @@ let HelixHeadlessBreadcrumb = class HelixHeadlessBreadcrumb extends HelixElement
23
23
  }
24
24
  renderSeparator() {
25
25
  return html `<slot name="separator"
26
- ><svg part="separator-mark" fill="currentColor" viewBox=${caretRight.viewBox}>
26
+ ><svg part="separator-mark" data-mirror fill="currentColor" viewBox=${caretRight.viewBox}>
27
27
  ${unsafeSVG(caretRight.content)}
28
28
  </svg></slot
29
29
  >`;
@@ -191,6 +191,9 @@ export declare class HelixHeadlessCarousel extends HelixElement {
191
191
  * changes the slide, because an indicator that could be focused without
192
192
  * selecting would leave the highlight and the slide disagreeing with nothing
193
193
  * on screen saying which is which.
194
+ *
195
+ * Along the line, so on a right-to-left page, where the first indicator is on
196
+ * the right, the left arrow is the one that moves on.
194
197
  */
195
198
  private readonly handleIndicatorKeydown;
196
199
  /** Moves to a slide, wrapping only where `loop` says to. */
@@ -224,6 +227,15 @@ export declare class HelixHeadlessCarousel extends HelixElement {
224
227
  * to index 0 put its edge back on the clip edge. Measured on the insights
225
228
  * carousel: `scrollLeft` resting at 4 against a 4px bleed, the first card
226
229
  * shaved, and no scrolling done to cause it.
230
+ *
231
+ * **On a right-to-left track the leading edge is the right one**, and
232
+ * `scrollLeft` counts down from zero as the track moves on. Measured from the
233
+ * left, a carousel showing one slide at a time happened to come out right,
234
+ * each slide a whole track to the left of the one before it; one showing
235
+ * three put every one of the first few slides at a positive offset the
236
+ * scroller cannot reach, so it clamped to zero and the next arrow moved the
237
+ * dots and not the slides. Measured in Chromium on the several-across
238
+ * example: three presses of next, `index` at 2 and `scrollLeft` still at 0.
227
239
  */
228
240
  private edgeOf;
229
241
  private scrollToIndex;
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement, HelixSelectEvent, hostAria, requestChange, } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, HelixSelectEvent, hostAria, inlineStep, requestChange, } from '@fusion.dev/helix-core';
8
8
  import { caretLeft, caretRight, play, stop } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -21,7 +21,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
21
21
  this.loop = false;
22
22
  this.rotating = false;
23
23
  this.handleIndicatorKeydown = (event) => {
24
- const step = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;
24
+ const step = inlineStep(this, event.key);
25
25
  if (step === 0) {
26
26
  return;
27
27
  }
@@ -121,9 +121,13 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
121
121
  return Number.isNaN(read) ? 0 : read;
122
122
  }
123
123
  edgeOf(slide, track, bleed) {
124
- return this.orientation === 'vertical'
125
- ? slide.offsetTop - track.offsetTop - bleed
126
- : slide.offsetLeft - track.offsetLeft - bleed;
124
+ if (this.orientation === 'vertical') {
125
+ return slide.offsetTop - track.offsetTop - bleed;
126
+ }
127
+ if (getComputedStyle(track).direction === 'rtl') {
128
+ return slide.offsetLeft + slide.offsetWidth - (track.offsetLeft + track.offsetWidth) + bleed;
129
+ }
130
+ return slide.offsetLeft - track.offsetLeft - bleed;
127
131
  }
128
132
  scrollToIndex() {
129
133
  const slide = this.panes[this.index];
@@ -264,7 +268,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
264
268
  aria-label="Previous slide"
265
269
  @click=${() => this.goTo(this.index - 1)}
266
270
  >
267
- <svg part="previous-mark" fill="currentColor" viewBox=${caretLeft.viewBox} aria-hidden="true">
271
+ <svg part="previous-mark" data-mirror fill="currentColor" viewBox=${caretLeft.viewBox} aria-hidden="true">
268
272
  ${unsafeSVG(caretLeft.content)}
269
273
  </svg>
270
274
  </button>
@@ -274,7 +278,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
274
278
  aria-label="Next slide"
275
279
  @click=${() => this.goTo(this.index + 1)}
276
280
  >
277
- <svg part="next-mark" fill="currentColor" viewBox=${caretRight.viewBox} aria-hidden="true">
281
+ <svg part="next-mark" data-mirror fill="currentColor" viewBox=${caretRight.viewBox} aria-hidden="true">
278
282
  ${unsafeSVG(caretRight.content)}
279
283
  </svg>
280
284
  </button>`}
@@ -110,6 +110,10 @@ export declare class HelixHeadlessChatComposer extends HelixElement {
110
110
  * and the key are one affordance and should look like it. `send-label` is the
111
111
  * accessible name rather than a visible one, so a screen reader still hears
112
112
  * the word.
113
+ *
114
+ * **Not mirrored on a right-to-left page**, where every caret meaning next
115
+ * is. It pictures a key rather than a way to go, like the arrows `Kbd`
116
+ * draws, and a picture of a key is not turned round with the text.
113
117
  */
114
118
  protected renderSend(): TemplateResult;
115
119
  /**
@@ -59,6 +59,15 @@ declare const HelixHeadlessChat_base: (new (...args: any[]) => import("@fusion.d
59
59
  * too long to hold as elements: it is drawn a window at a time, measured as it
60
60
  * goes, and the log needs a block size of its own for that to mean anything.
61
61
  *
62
+ * **A fed turn is styled through this element, not its own.** Its message is
63
+ * drawn in this shadow root, where `[author="me"]` cannot reach it, so every
64
+ * fed turn's parts are forwarded as `message-*`, and the ones that change with
65
+ * the turn a second time while it holds: `-mine` for a turn by `me`, and
66
+ * `message-meta-failed`, `message-content-sending` and
67
+ * `message-content-streaming` for its state. Every other author has the plain
68
+ * names only, so a conversation styling each participant apart passes its
69
+ * turns as children.
70
+ *
62
71
  * @since 0.1.0
63
72
  * @status experimental
64
73
  * @category feedback
@@ -89,11 +98,19 @@ declare const HelixHeadlessChat_base: (new (...args: any[]) => import("@fusion.d
89
98
  * @csspart message - A turn fed as data: the message drawn for it, forwarded whole.
90
99
  * @csspart message-actions - The controls offered on a fed turn, beside its time.
91
100
  * @csspart message-avatar - A fed turn's leading slot's box.
101
+ * @csspart message-avatar-mine - The leading slot's box on a fed turn by `me`.
92
102
  * @csspart message-body - What a fed turn said, and the line under it.
103
+ * @csspart message-body-mine - What a fed turn by `me` said, and the line under it.
93
104
  * @csspart message-content - A fed turn's text.
105
+ * @csspart message-content-mine - The text of a fed turn by `me`.
106
+ * @csspart message-content-sending - A fed turn's text while it is `sending`.
107
+ * @csspart message-content-streaming - A fed turn's text while it is `streaming`.
94
108
  * @csspart message-indicator - A fed turn's default wait.
95
109
  * @csspart message-mark - The status glyph beside a fed turn's failure.
96
110
  * @csspart message-meta - The line under a fed turn: its time, its state, and its controls.
111
+ * @csspart message-meta-failed - The line under a fed turn that `failed`, which says so.
112
+ * @csspart message-meta-mine - The line under a fed turn by `me`.
113
+ * @csspart message-mine - A fed turn by `me`: the message drawn for it.
97
114
  * @csspart message-retry - The control offered on a fed turn that failed.
98
115
  * @csspart message-sources - What a fed turn was drawn from.
99
116
  * @csspart message-state - What has happened to a fed turn, where that is worth saying.
@@ -13,6 +13,17 @@ import { repeat } from 'lit/directives/repeat.js';
13
13
  import { html } from 'lit/static-html.js';
14
14
  import { FAILED_LABEL } from '../message/chat-message.js';
15
15
  const REGIONS = ['header', 'actions', 'resume', 'status', 'composer'];
16
+ const SECOND_NAMES = {
17
+ author: {
18
+ me: 'avatar: message-avatar-mine, body: message-body-mine, content: message-content-mine, message: message-mine, meta: message-meta-mine',
19
+ },
20
+ state: {
21
+ failed: 'meta: message-meta-failed',
22
+ sending: 'content: message-content-sending',
23
+ streaming: 'content: message-content-streaming',
24
+ },
25
+ };
26
+ const secondNames = (table, key) => key !== undefined && Object.hasOwn(table, key) ? `, ${table[key]}` : '';
16
27
  const settled = (turn) => turn.state !== 'sending' && turn.state !== 'streaming';
17
28
  const newsworthy = (turn) => turn.author !== 'me' || turn.state === 'failed';
18
29
  const spoken = (message) => [...message.childNodes]
@@ -394,7 +405,7 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
394
405
  exportparts="actions: message-actions, avatar: message-avatar, body: message-body,
395
406
  content: message-content, indicator: message-indicator, mark: message-mark, message,
396
407
  meta: message-meta, retry: message-retry, sources: message-sources,
397
- state: message-state, time: message-time"
408
+ state: message-state, time: message-time${secondNames(SECOND_NAMES.author, turn.author)}${secondNames(SECOND_NAMES.state, turn.state)}"
398
409
  author=${turn.author ?? nothing}
399
410
  at=${turn.at ?? nothing}
400
411
  state=${turn.state ?? nothing}
@@ -53,15 +53,23 @@ import '../../copy-button/index.js';
53
53
  * @csspart block - The scrolling `<pre>`.
54
54
  * @csspart code - The `<code>` inside it.
55
55
  * @csspart context - In a diff, a line both versions share.
56
- * @csspart copy - The copy button.
56
+ * @csspart copy - The copy button: in the header where there is one, and otherwise beside the code.
57
57
  * @csspart copy-button - The inner button.
58
58
  * @csspart copy-mark - The clipboard glyph, and the confirmation that replaces it.
59
59
  * @csspart copy-tooltip - The bubble, forwarded from the tooltip inside.
60
60
  * @csspart copy-tooltip-arrow - The point, resting against the trigger.
61
+ * @csspart copy-tooltip-arrow-bottom - The point while the bubble is below the copy button, so on its top edge, beside `copy-tooltip-arrow`.
62
+ * @csspart copy-tooltip-arrow-left - The point while the bubble is left of the copy button, so on its right edge, beside `copy-tooltip-arrow`.
63
+ * @csspart copy-tooltip-arrow-right - The point while the bubble is right of the copy button, so on its left edge, beside `copy-tooltip-arrow`.
64
+ * @csspart copy-tooltip-arrow-top - The point while the bubble is above the copy button, so on its bottom edge, beside `copy-tooltip-arrow`.
65
+ * @csspart copy-tooltip-bottom - The bubble while it is below the copy button, beside `copy-tooltip`.
66
+ * @csspart copy-tooltip-left - The bubble while it is left of the copy button, beside `copy-tooltip`.
67
+ * @csspart copy-tooltip-right - The bubble while it is right of the copy button, beside `copy-tooltip`.
68
+ * @csspart copy-tooltip-top - The bubble while it is above the copy button, beside `copy-tooltip`.
61
69
  * @csspart file - In a diff, one file's header and block.
62
70
  * @csspart filler - In a split diff, the empty row opposite a line the other side does not have.
63
- * @csspart frame - The code and the copy button beside it.
64
- * @csspart header - The bar carrying the name, where there is one.
71
+ * @csspart frame - The code, and the copy button beside it where there is no header.
72
+ * @csspart header - The bar carrying the name and the copy button, where there is a name.
65
73
  * @csspart hunk - In a diff, a `@@` line saying where the lines under it are.
66
74
  * @csspart label - The file name or language, where one is given.
67
75
  * @csspart marker - In a diff, the `+`, `-` or space that opens a line.
@@ -139,6 +147,20 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
139
147
  private get text();
140
148
  protected firstUpdated(changed: PropertyValues): void;
141
149
  protected render(): TemplateResult;
150
+ /**
151
+ * The name with the copy button beside it, or nothing when there is no name.
152
+ *
153
+ * **The button is in the header wherever there is one**, because beside the
154
+ * code it stands over the block and the block has to make room for it. A
155
+ * diff cannot: its washes run to the edge, so the button stood on the hunk
156
+ * line and the line under it. In the header it is over nothing.
157
+ *
158
+ * **No name draws no header**, rather than a bar to hold one button, which
159
+ * turned a `Usage` section of one-line imports into a run of empty strips.
160
+ * The button then stands beside the code, in room the block keeps for it.
161
+ */
162
+ private renderHeader;
163
+ private renderCopy;
142
164
  /**
143
165
  * The button that takes the code, behind a seam the styled tier can move.
144
166
  *
@@ -47,17 +47,28 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
47
47
  if (files.length > 0) {
48
48
  return this.renderDiff(files);
49
49
  }
50
- return html `${this.label ? html `<div part="header"><span part="label">${this.label}</span></div>` : nothing}
50
+ return html `${this.renderHeader(this.label)}
51
51
  <div part="frame">
52
52
  <pre part="block"><code part="code"><slot @slotchange=${() => this.requestUpdate()}></slot></code></pre>
53
- ${this.noCopy ? nothing : this.renderCopyButton()}
53
+ ${this.label ? nothing : this.renderCopy()}
54
54
  </div>`;
55
55
  }
56
+ renderHeader(name, value) {
57
+ return name
58
+ ? html `<div part="header"><span part="label">${name}</span>${this.renderCopy(value)}</div>`
59
+ : nothing;
60
+ }
61
+ renderCopy(value) {
62
+ return this.noCopy ? nothing : this.renderCopyButton(value);
63
+ }
56
64
  renderCopyButton(value = this.text) {
57
65
  return html `<${this.tag('copy-button')}
58
66
  part="copy"
59
67
  exportparts="button: copy-button, mark: copy-mark, tooltip: copy-tooltip,
60
- tooltip-arrow: copy-tooltip-arrow"
68
+ tooltip-arrow: copy-tooltip-arrow, tooltip-arrow-bottom: copy-tooltip-arrow-bottom,
69
+ tooltip-arrow-left: copy-tooltip-arrow-left, tooltip-arrow-right: copy-tooltip-arrow-right,
70
+ tooltip-arrow-top: copy-tooltip-arrow-top, tooltip-bottom: copy-tooltip-bottom,
71
+ tooltip-left: copy-tooltip-left, tooltip-right: copy-tooltip-right, tooltip-top: copy-tooltip-top"
61
72
  label="Copy code"
62
73
  .value=${value}
63
74
  ></${this.tag('copy-button')}>`;
@@ -99,12 +110,12 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
99
110
  .map((line) => line.text)
100
111
  .join('\n');
101
112
  return html `<div part="file">
102
- ${name ? html `<div part="header"><span part="label">${name}</span></div>` : nothing}
113
+ ${this.renderHeader(name, now)}
103
114
  <div part="frame">
104
115
  ${this.variant === 'split'
105
116
  ? this.renderSplit(file, width)
106
117
  : html `<pre part="block"><code part="code">${file.hunks.map((hunk) => html `${this.renderHunk(hunk)}${hunk.lines.map((line) => this.renderLine(line, width))}`)}</code></pre>`}
107
- ${this.noCopy ? nothing : this.renderCopyButton(now)}
118
+ ${name ? nothing : this.renderCopy(now)}
108
119
  </div>
109
120
  </div>`;
110
121
  })}<slot hidden @slotchange=${() => this.requestUpdate()}></slot>`;
@@ -87,7 +87,8 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
87
87
  if (box.width === 0 || box.height === 0) {
88
88
  return;
89
89
  }
90
- const across = Math.min(1, Math.max(0, (event.clientX - box.left) / box.width));
90
+ const fromLeft = Math.min(1, Math.max(0, (event.clientX - box.left) / box.width));
91
+ const across = getComputedStyle(grid).direction === 'rtl' ? 1 - fromLeft : fromLeft;
91
92
  const down = Math.min(1, Math.max(0, (event.clientY - box.top) / box.height));
92
93
  this.move({ brightness: Math.round((1 - down) * 100), saturation: Math.round(across * 100) });
93
94
  };
@@ -31,6 +31,14 @@ import '../../tooltip/index.js';
31
31
  * @csspart mark - The clipboard glyph, and the confirmation that replaces it.
32
32
  * @csspart tooltip - The bubble, forwarded from the tooltip inside.
33
33
  * @csspart tooltip-arrow - The point, resting against the trigger.
34
+ * @csspart tooltip-arrow-bottom - The point while the bubble is below the button, so on its top edge, beside `tooltip-arrow`.
35
+ * @csspart tooltip-arrow-left - The point while the bubble is left of the button, so on its right edge, beside `tooltip-arrow`.
36
+ * @csspart tooltip-arrow-right - The point while the bubble is right of the button, so on its left edge, beside `tooltip-arrow`.
37
+ * @csspart tooltip-arrow-top - The point while the bubble is above the button, so on its bottom edge, beside `tooltip-arrow`.
38
+ * @csspart tooltip-bottom - The bubble while it is below the button, beside `tooltip`.
39
+ * @csspart tooltip-left - The bubble while it is left of the button, beside `tooltip`.
40
+ * @csspart tooltip-right - The bubble while it is right of the button, beside `tooltip`.
41
+ * @csspart tooltip-top - The bubble while it is above the button, beside `tooltip`.
34
42
  */
35
43
  export declare class HelixHeadlessCopyButton extends HelixHeadlessIconButton {
36
44
  /**
@@ -61,7 +61,10 @@ let HelixHeadlessCopyButton = HelixHeadlessCopyButton_1 = class HelixHeadlessCop
61
61
  }
62
62
  renderTooltip(control) {
63
63
  return html `<${this.tag('tooltip')} content=${this.says} persist
64
- exportparts="arrow: tooltip-arrow, tooltip">
64
+ exportparts="arrow: tooltip-arrow, arrow-bottom: tooltip-arrow-bottom,
65
+ arrow-left: tooltip-arrow-left, arrow-right: tooltip-arrow-right,
66
+ arrow-top: tooltip-arrow-top, tooltip, tooltip-bottom, tooltip-left, tooltip-right,
67
+ tooltip-top">
65
68
  ${control}
66
69
  </${this.tag('tooltip')}>`;
67
70
  }
@@ -371,6 +371,16 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
371
371
  * where it was written: it has nothing to be named by.
372
372
  */
373
373
  get orderedColumns(): HelixHeadlessTableColumn[];
374
+ /**
375
+ * The columns drawn: the arranged ones less any that are hidden.
376
+ *
377
+ * **A hidden column takes no track and draws no cells.** Left in, its
378
+ * heading went and its track and its cell in every row stayed, so the header
379
+ * row came up a heading short, the first cell filled the gap, and every row
380
+ * after it began a column late. It keeps its place in `order` and in the
381
+ * sort, which are by field, so showing it again puts it back where it was.
382
+ */
383
+ private get shownColumns();
374
384
  /** The fields in the order on screen. */
375
385
  private get fields();
376
386
  /** The columns reduced to what the ordering needs. */
@@ -474,16 +484,25 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
474
484
  private readonly toggleRow;
475
485
  /** Selects every row, or clears them all where every one already was. */
476
486
  private readonly toggleAll;
477
- /** Moves a column by some places among the ones that move. */
487
+ /**
488
+ * Moves a column by some places among the ones that move and are drawn.
489
+ *
490
+ * Counted among the drawn ones, so a key moves the heading past one a reader
491
+ * can see: counted among all of them, a step past a hidden column changed the
492
+ * order and nothing on screen. A hidden column keeps its place among the rest.
493
+ */
478
494
  private moveColumn;
495
+ /** Every field in order, with one taken out and put back beside another. */
496
+ private placed;
479
497
  /**
480
498
  * The result as CSV: every row the filter lets through, in the order on
481
499
  * screen, in the columns on screen, headed by their headings.
482
500
  *
483
501
  * **Values, not cells.** A cell may be a template, a badge or a link, so each
484
502
  * column gives its field's value, which is what a spreadsheet wants anyway.
485
- * A column with no field has no value and is left out. In `server` mode this
486
- * is the page it holds, which is all it can know.
503
+ * A column with no field has no value and is left out, and so is a hidden
504
+ * one, which is not on screen. In `server` mode this is the page it holds,
505
+ * which is all it can know.
487
506
  *
488
507
  * **A text value that a spreadsheet would run is quoted as text.** A cell
489
508
  * opening with `=`, `+`, `-` or `@` is a formula to a spreadsheet, and a
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var HelixHeadlessDataTable_1;
8
- import { customElement, HelixElement, HelixFilterEvent, HelixNavigateEvent, HelixReorderEvent, HelixSelectEvent, HelixSortEvent, hostAria, MixinCollection, requestChange, slotFilled, VirtualizeController, } from '@fusion.dev/helix-core';
8
+ import { customElement, HelixElement, HelixFilterEvent, HelixNavigateEvent, HelixReorderEvent, HelixSelectEvent, HelixSortEvent, hostAria, inlineStep, MixinCollection, requestChange, slotFilled, VirtualizeController, } from '@fusion.dev/helix-core';
9
9
  import { nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
11
  import { repeat } from 'lit/directives/repeat.js';
@@ -99,8 +99,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
99
99
  return;
100
100
  }
101
101
  const column = this.columnFrom(event);
102
- const forward = getComputedStyle(this).direction === 'rtl' ? -1 : 1;
103
- const by = event.key === 'ArrowRight' ? forward : event.key === 'ArrowLeft' ? -forward : 0;
102
+ const by = inlineStep(this, event.key);
104
103
  if (column && by !== 0) {
105
104
  event.preventDefault();
106
105
  this.moveColumn(column.field, by);
@@ -126,7 +125,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
126
125
  return;
127
126
  }
128
127
  const rtl = getComputedStyle(this).direction === 'rtl';
129
- const others = this.orderedColumns.filter((column) => column.field !== '' && column.field !== dragging.field);
128
+ const others = this.shownColumns.filter((column) => column.field !== '' && column.field !== dragging.field);
130
129
  const place = others.filter((column) => {
131
130
  const box = column.shadowRoot?.querySelector('[part="column"]')?.getBoundingClientRect();
132
131
  if (!box) {
@@ -135,8 +134,11 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
135
134
  const middle = box.left + box.width / 2;
136
135
  return rtl ? event.clientX < middle : event.clientX > middle;
137
136
  }).length;
138
- const next = others.map((column) => column.field);
139
- next.splice(place, 0, dragging.field);
137
+ const beside = others[place - 1] ?? others[0];
138
+ if (!beside) {
139
+ return;
140
+ }
141
+ const next = this.placed(dragging.field, beside.field, place > 0);
140
142
  if (next.join(' ') !== this.dragOrder.join(' ')) {
141
143
  this.dragOrder = next;
142
144
  }
@@ -272,6 +274,9 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
272
274
  let next = 0;
273
275
  return columns.map((column) => (column.field === '' ? column : (moving[next++] ?? column)));
274
276
  }
277
+ get shownColumns() {
278
+ return this.orderedColumns.filter((column) => column.shown);
279
+ }
275
280
  get fields() {
276
281
  return this.orderedColumns.filter((column) => column.field !== '').map((column) => column.field);
277
282
  }
@@ -281,7 +286,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
281
286
  .map((column) => ({ field: column.field, order: (row) => column.order(row) }));
282
287
  }
283
288
  get template() {
284
- const declared = this.orderedColumns;
289
+ const declared = this.shownColumns;
285
290
  if (declared.length === 0) {
286
291
  return '';
287
292
  }
@@ -408,17 +413,21 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
408
413
  return rows.map((row, place) => this.keyOf(row, place));
409
414
  }
410
415
  moveColumn(field, by) {
411
- const fields = this.fields;
412
- const from = fields.indexOf(field);
413
- const to = from + by;
414
- if (from < 0 || to < 0 || to >= fields.length) {
416
+ const drawn = this.shownColumns.filter((column) => column.field !== '');
417
+ const from = drawn.findIndex((column) => column.field === field);
418
+ const past = drawn[from + by];
419
+ if (from < 0 || !past) {
415
420
  return false;
416
421
  }
417
- fields.splice(to, 0, ...fields.splice(from, 1));
418
- return this.requestOrder(fields);
422
+ return this.requestOrder(this.placed(field, past.field, by > 0));
423
+ }
424
+ placed(field, beside, after) {
425
+ const fields = this.fields.filter((one) => one !== field);
426
+ fields.splice(fields.indexOf(beside) + (after ? 1 : 0), 0, field);
427
+ return fields;
419
428
  }
420
429
  csv() {
421
- const columns = this.orderedColumns.filter((column) => column.field !== '');
430
+ const columns = this.shownColumns.filter((column) => column.field !== '');
422
431
  const rows = this.mode === 'server' ? this.rows : this.arrange().rows;
423
432
  const quote = (value) => {
424
433
  if (value === undefined || value === null) {
@@ -559,7 +568,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
559
568
  ></${checkbox}>`;
560
569
  }
561
570
  renderRows(rows) {
562
- const columns = this.orderedColumns;
571
+ const columns = this.shownColumns;
563
572
  const field = this.rowKey;
564
573
  const start = this.windowStart;
565
574
  const chosen = this.selectable ? this.chosen : undefined;
@@ -611,7 +620,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
611
620
  render() {
612
621
  const { available, matched, rows } = this.view;
613
622
  const template = this.template;
614
- const columns = this.tableColumns;
623
+ const columns = this.shownColumns;
615
624
  const pagination = this.tag('pagination');
616
625
  return html `<div part="toolbar"><slot name="toolbar"></slot></div>
617
626
  <div
@@ -145,9 +145,42 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
145
145
  *
146
146
  * Worth more than one mainly for a range, where picking a start in March and
147
147
  * an end in April otherwise means paging between them and losing sight of the
148
- * first. The panel is sized by its content, so this widens it.
148
+ * first. The panel is sized by its content, so this widens it, and where the
149
+ * window has no room for that width it shows one month until there is.
149
150
  */
150
151
  months: number;
152
+ /**
153
+ * How many months the panel is showing, where that is fewer than `months`.
154
+ *
155
+ * **One month rather than a squeezed two**, and decided here rather than in a
156
+ * stylesheet because what changes is markup. Two months measure 600 pixels
157
+ * across, measured 15 Sep 2026, and in a 390 window that ran past both
158
+ * edges. A rule could only clip them, which hides the next-month control with
159
+ * the month it sits on, or stack them, which makes a panel taller than most
160
+ * of a phone. The count is behavior, as a carousel's per-view is.
161
+ */
162
+ private fitted;
163
+ /**
164
+ * How wide the panel was the last time it held every month, in pixels.
165
+ *
166
+ * Measured rather than estimated, because a month's width is its locale's:
167
+ * the weekday names set it. Remembered, so a panel showing one month knows
168
+ * what it would take to show them all, and the answer cannot flip back and
169
+ * forth between two measurements of different things.
170
+ */
171
+ private wide;
172
+ /**
173
+ * Shows one month where the window has no room for them all, and all of them
174
+ * again once it does.
175
+ *
176
+ * Called after every placement, with the room the floating pass measured,
177
+ * which is the window less a margin on each side. The panel hangs in the top
178
+ * layer, so the window is its box, the argument Dialog makes for reading the
179
+ * viewport. The surface's own width is read, since it is sized by its content
180
+ * and never capped.
181
+ */
182
+ protected placed(room: number | undefined): void;
183
+ protected willUpdate(changed: PropertyValues): void;
151
184
  /**
152
185
  * What the field says before a date is in it.
153
186
  */
@@ -33,6 +33,8 @@ let HelixHeadlessDateInput = class HelixHeadlessDateInput extends MixinPickerEdi
33
33
  this.max = '';
34
34
  this.min = '';
35
35
  this.months = 1;
36
+ this.fitted = undefined;
37
+ this.wide = undefined;
36
38
  this.placeholder = 'YYYY-MM-DD';
37
39
  this.step = 1;
38
40
  this.draft = '';
@@ -82,6 +84,27 @@ let HelixHeadlessDateInput = class HelixHeadlessDateInput extends MixinPickerEdi
82
84
  };
83
85
  this.triggerLabel = 'Choose a date';
84
86
  }
87
+ placed(room) {
88
+ const all = Math.max(1, Math.floor(this.months) || 1);
89
+ const surface = this.partNamed('surface');
90
+ if (room === undefined || all === 1 || !surface) {
91
+ return;
92
+ }
93
+ if (this.fitted === undefined) {
94
+ this.wide = surface.offsetWidth;
95
+ }
96
+ const next = this.wide === undefined || this.wide <= room ? undefined : 1;
97
+ if (next !== this.fitted) {
98
+ this.fitted = next;
99
+ }
100
+ }
101
+ willUpdate(changed) {
102
+ super.willUpdate(changed);
103
+ if (changed.has('months') || changed.has('locale')) {
104
+ this.fitted = undefined;
105
+ this.wide = undefined;
106
+ }
107
+ }
85
108
  get picked() {
86
109
  const held = dates(this.value);
87
110
  return held.length > 0 && held.every(isIso) ? held.join(',') : '';
@@ -153,7 +176,7 @@ let HelixHeadlessDateInput = class HelixHeadlessDateInput extends MixinPickerEdi
153
176
  week: picker-week, weekday: picker-weekday"
154
177
  ?invalid=${this.resolvedFeedback !== ''}
155
178
  mode=${this.mode ?? nothing}
156
- months=${this.months}
179
+ months=${this.fitted ?? this.months}
157
180
  .value=${this.picked}
158
181
  disable-dates=${this.disableDates || nothing}
159
182
  disable-days=${this.disableDays || nothing}
@@ -274,6 +297,9 @@ __decorate([
274
297
  __decorate([
275
298
  property({ type: Number })
276
299
  ], HelixHeadlessDateInput.prototype, "months", void 0);
300
+ __decorate([
301
+ state()
302
+ ], HelixHeadlessDateInput.prototype, "fitted", void 0);
277
303
  __decorate([
278
304
  property()
279
305
  ], HelixHeadlessDateInput.prototype, "placeholder", void 0);