@redvars/peacock 3.6.1 → 3.6.3

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 (120) hide show
  1. package/dist/assets/components.css.map +1 -1
  2. package/dist/assets/styles.css +1 -1
  3. package/dist/assets/styles.css.map +1 -1
  4. package/dist/assets/tokens.css +1 -1
  5. package/dist/assets/tokens.css.map +1 -1
  6. package/dist/{button-colors-Ccys3hvS.js → button-colors-Cg6oxiz-.js} +126 -116
  7. package/dist/{button-colors-Ccys3hvS.js.map → button-colors-Cg6oxiz-.js.map} +1 -1
  8. package/dist/button-group.js +2 -2
  9. package/dist/button.js +18 -16
  10. package/dist/button.js.map +1 -1
  11. package/dist/canvas.js +126 -107
  12. package/dist/canvas.js.map +1 -1
  13. package/dist/card.js +1 -1
  14. package/dist/card.js.map +1 -1
  15. package/dist/code-highlighter.js +34 -9
  16. package/dist/code-highlighter.js.map +1 -1
  17. package/dist/custom-elements-jsdocs.json +4306 -3215
  18. package/dist/custom-elements.json +8344 -7173
  19. package/dist/{flow-designer-node-BWrPuxAR.js → flow-designer-node-9Bqyn6qx.js} +2 -1
  20. package/dist/flow-designer-node-9Bqyn6qx.js.map +1 -0
  21. package/dist/flow-designer-node.js +1 -1
  22. package/dist/flow-designer.js +1402 -8
  23. package/dist/flow-designer.js.map +1 -1
  24. package/dist/icon-CueRR7wx.js +260 -0
  25. package/dist/icon-CueRR7wx.js.map +1 -0
  26. package/dist/{icon-button-CK1ZuE-2.js → icon-button-AdJBEoNy.js} +34 -30
  27. package/dist/icon-button-AdJBEoNy.js.map +1 -0
  28. package/dist/index.js +10 -9
  29. package/dist/index.js.map +1 -1
  30. package/dist/modal.js +11 -11
  31. package/dist/modal.js.map +1 -1
  32. package/dist/{navigation-rail-DTTkqohi.js → navigation-rail-DAUuJ_Yp.js} +975 -486
  33. package/dist/navigation-rail-DAUuJ_Yp.js.map +1 -0
  34. package/dist/peacock-loader.js +33 -30
  35. package/dist/peacock-loader.js.map +1 -1
  36. package/dist/{popover-NC7b1lTq.js → popover-DUPmMVWS.js} +9 -4
  37. package/dist/{popover-NC7b1lTq.js.map → popover-DUPmMVWS.js.map} +1 -1
  38. package/dist/popover-content.js +1 -1
  39. package/dist/popover-content.js.map +1 -1
  40. package/dist/popover.js +1 -1
  41. package/dist/search.js +11 -14
  42. package/dist/search.js.map +1 -1
  43. package/dist/src/__controllers/floating-controller.d.ts +1 -0
  44. package/dist/src/avatar/avatar.d.ts +1 -1
  45. package/dist/src/breadcrumb/breadcrumb/breadcrumb.d.ts +0 -1
  46. package/dist/src/canvas/canvas.d.ts +3 -3
  47. package/dist/src/chip/chip/chip.d.ts +14 -11
  48. package/dist/src/chip/chip-set/chip-set.d.ts +20 -0
  49. package/dist/src/chip/chip-set/index.d.ts +1 -0
  50. package/dist/src/code-highlighter/code-highlighter.d.ts +4 -0
  51. package/dist/src/field/field.d.ts +1 -0
  52. package/dist/src/flow-designer/flow-designer-node.d.ts +1 -0
  53. package/dist/src/image/image.d.ts +2 -2
  54. package/dist/src/index.d.ts +2 -0
  55. package/dist/src/input/input.d.ts +1 -3
  56. package/dist/src/item/index.d.ts +1 -0
  57. package/dist/src/item/item.d.ts +48 -0
  58. package/dist/src/menu/menu/menu.d.ts +1 -0
  59. package/dist/src/menu/menu-item/menu-item.d.ts +8 -9
  60. package/dist/src/menu/sub-menu/sub-menu.d.ts +1 -0
  61. package/dist/src/modal/modal.d.ts +1 -1
  62. package/dist/src/navigation-rail/navigation-rail.d.ts +2 -6
  63. package/dist/src/popover/popover-content.d.ts +1 -1
  64. package/dist/src/search/search.d.ts +2 -6
  65. package/dist/test/chip.test.d.ts +1 -0
  66. package/dist/test/item.test.d.ts +1 -0
  67. package/dist/tsconfig.tsbuildinfo +1 -1
  68. package/package.json +1 -1
  69. package/readme.md +2 -2
  70. package/scss/mixin.scss +23 -0
  71. package/scss/styles.scss +3 -3
  72. package/scss/tokens.css +1 -1
  73. package/src/__controllers/floating-controller.ts +9 -3
  74. package/src/avatar/avatar.scss +4 -4
  75. package/src/avatar/avatar.ts +1 -1
  76. package/src/breadcrumb/breadcrumb/breadcrumb.ts +0 -1
  77. package/src/button/button/button-sizes.scss +11 -11
  78. package/src/button/button/button.scss +96 -122
  79. package/src/button/button/button.ts +38 -36
  80. package/src/button/icon-button/icon-button-sizes.scss +8 -8
  81. package/src/button/icon-button/icon-button.ts +23 -20
  82. package/src/canvas/canvas.scss +18 -6
  83. package/src/canvas/canvas.ts +125 -103
  84. package/src/card/card.ts +1 -1
  85. package/src/chip/chip/chip.scss +120 -46
  86. package/src/chip/chip/chip.ts +97 -38
  87. package/src/chip/chip-set/chip-set.scss +13 -0
  88. package/src/chip/chip-set/chip-set.ts +25 -0
  89. package/src/chip/chip-set/index.ts +1 -0
  90. package/src/code-highlighter/code-highlighter.ts +33 -6
  91. package/src/empty-state/empty-state.scss +1 -0
  92. package/src/field/field.scss +1 -1
  93. package/src/field/field.ts +6 -0
  94. package/src/flow-designer/flow-designer-node.ts +1 -0
  95. package/src/image/image.scss +21 -16
  96. package/src/image/image.ts +13 -14
  97. package/src/index.ts +2 -0
  98. package/src/input/input.ts +16 -25
  99. package/src/item/index.ts +1 -0
  100. package/src/item/item.scss +184 -0
  101. package/src/item/item.ts +340 -0
  102. package/src/menu/menu/menu.ts +16 -9
  103. package/src/menu/menu-item/menu-item.scss +30 -108
  104. package/src/menu/menu-item/menu-item.ts +89 -129
  105. package/src/menu/sub-menu/sub-menu.ts +6 -2
  106. package/src/modal/modal.scss +10 -10
  107. package/src/modal/modal.ts +1 -1
  108. package/src/navigation-rail/navigation-rail.ts +2 -6
  109. package/src/peacock-loader.ts +28 -22
  110. package/src/popover/popover-content.ts +1 -1
  111. package/src/search/search.ts +11 -16
  112. package/src/select/option.ts +1 -1
  113. package/src/select/select.scss +1 -10
  114. package/src/select/select.ts +2 -0
  115. package/dist/flow-designer-DvTUrDp5.js +0 -1656
  116. package/dist/flow-designer-DvTUrDp5.js.map +0 -1
  117. package/dist/flow-designer-node-BWrPuxAR.js.map +0 -1
  118. package/dist/icon-button-CK1ZuE-2.js.map +0 -1
  119. package/dist/navigation-rail-DTTkqohi.js.map +0 -1
  120. package/src/chip/chip/chip-colors.scss +0 -31
@@ -74,36 +74,36 @@ export class Button extends BaseButton {
74
74
  * Type is preset of color and variant. Type will be only applied.
75
75
  *
76
76
  */
77
- @property({ type: String }) type?: 'primary' | 'secondary' | 'tertiary';
78
-
79
- /**
80
- * The visual style of the button.
81
- *
82
- * Possible variant values:
83
- * `"filled"` is a filled button.
84
- * `"outlined"` is an outlined button.
85
- * `"text"` is a transparent button.
86
- * `"tonal"` is a light color button.
87
- * `"elevated"` is elevated button
88
- */
89
- @property() variant:
90
- | 'elevated'
91
- | 'filled'
92
- | 'tonal'
93
- | 'outlined'
94
- | 'text'
95
- | 'neo' = 'filled';
96
-
97
- /**
98
- * Defines the primary color of the button. This can be set to predefined color names to apply specific color themes.
99
- */
100
- @property({ reflect: true }) color:
101
- | 'primary'
102
- | 'success'
103
- | 'danger'
104
- | 'warning'
105
- | 'surface'
106
- | 'on-surface' = 'primary';
77
+ @property({ type: String }) type?: 'primary' | 'secondary' | 'tertiary';
78
+
79
+ /**
80
+ * The visual style of the button.
81
+ *
82
+ * Possible variant values:
83
+ * `"filled"` is a filled button.
84
+ * `"outlined"` is an outlined button.
85
+ * `"text"` is a transparent button.
86
+ * `"tonal"` is a light color button.
87
+ * `"elevated"` is elevated button
88
+ */
89
+ @property() variant:
90
+ | 'elevated'
91
+ | 'filled'
92
+ | 'tonal'
93
+ | 'outlined'
94
+ | 'text'
95
+ | 'neo' = 'filled';
96
+
97
+ /**
98
+ * Defines the primary color of the button. This can be set to predefined color names to apply specific color themes.
99
+ */
100
+ @property({ reflect: true }) color:
101
+ | 'primary'
102
+ | 'success'
103
+ | 'danger'
104
+ | 'warning'
105
+ | 'surface'
106
+ | 'on-surface' = 'primary';
107
107
 
108
108
  /**
109
109
  * Additional ARIA attributes to pass to the inner button/anchor element.
@@ -155,11 +155,9 @@ export class Button extends BaseButton {
155
155
  }
156
156
 
157
157
  override render() {
158
- const isLink = this.__isLink();
159
158
 
160
- const cssClasses = {
159
+ const cssClasses: any = {
161
160
  button: true,
162
- 'button-element': true,
163
161
  [`size-${this.size}`]: true,
164
162
  [`variant-${this.variant}`]: true,
165
163
  [`color-${this.color}`]: true,
@@ -170,7 +168,9 @@ export class Button extends BaseButton {
170
168
  [`icon-align-${this.iconAlign}`]: true,
171
169
  };
172
170
 
173
- if (!isLink) {
171
+ if (!this.__isLink()) {
172
+ cssClasses['native-button'] = true;
173
+
174
174
  return html`<button
175
175
  class=${classMap(cssClasses)}
176
176
  id="button"
@@ -189,8 +189,9 @@ export class Button extends BaseButton {
189
189
  ${this.renderButtonContent()}
190
190
  </button>
191
191
  ${this.__renderTooltip()}`;
192
- }
193
- return html`<a
192
+ } else {
193
+ cssClasses['native-link'] = true;
194
+ return html`<a
194
195
  class=${classMap(cssClasses)}
195
196
  id="button"
196
197
  href=${this.href}
@@ -211,6 +212,7 @@ export class Button extends BaseButton {
211
212
  ${this.renderButtonContent()}
212
213
  </a>
213
214
  ${this.__renderTooltip()}`;
215
+ }
214
216
  }
215
217
 
216
218
  renderButtonContent() {
@@ -1,9 +1,9 @@
1
1
  @use '../../../scss/mixin';
2
2
 
3
3
  .button {
4
- --_container-padding: 0.75rem;
4
+ --private-button-container-padding: 0.75rem;
5
5
  width: var(--button-height);
6
- --_container-padding: 0;
6
+ --private-button-container-padding: 0;
7
7
  }
8
8
 
9
9
  :host([size='xs']),
@@ -13,7 +13,7 @@
13
13
 
14
14
  :host([size='xs']) .button,
15
15
  :host([size='extra-small']) .button {
16
- --_button-icon-size: 1rem;
16
+ --private-button-icon-size: 1rem;
17
17
  }
18
18
 
19
19
 
@@ -24,8 +24,8 @@
24
24
 
25
25
  :host([size='sm']) .button,
26
26
  :host([size='small']) .button {
27
- --_button-icon-size: 1.25rem;
28
- --_button-icon-label-spacing: 0.5rem;
27
+ --private-button-icon-size: 1.25rem;
28
+ --private-button-icon-label-spacing: 0.5rem;
29
29
  }
30
30
 
31
31
  :host([size='md']),
@@ -35,7 +35,7 @@
35
35
 
36
36
  :host([size='md']) .button,
37
37
  :host([size='medium']) .button {
38
- --_button-icon-size: 1.5rem;
38
+ --private-button-icon-size: 1.5rem;
39
39
  }
40
40
 
41
41
  :host([size='lg']),
@@ -45,7 +45,7 @@
45
45
 
46
46
  :host([size='lg']) .button,
47
47
  :host([size='large']) .button {
48
- --_button-icon-size: 2rem;
48
+ --private-button-icon-size: 2rem;
49
49
  }
50
50
 
51
51
  :host([size='xl']) {
@@ -53,5 +53,5 @@
53
53
  }
54
54
 
55
55
  :host([size='xl']) .button {
56
- --_button-icon-size: 2.5rem;
56
+ --private-button-icon-size: 2.5rem;
57
57
  }
@@ -149,6 +149,7 @@ export class IconButton extends BaseButton {
149
149
  };
150
150
 
151
151
  if (!isLink) {
152
+ cssClasses['native-button'] = true;
152
153
  return html`<button
153
154
  class=${classMap(cssClasses)}
154
155
  id="button"
@@ -167,27 +168,29 @@ export class IconButton extends BaseButton {
167
168
  ${this.renderButtonContent()}
168
169
  </button>
169
170
  ${this.__renderTooltip()}`;
170
- }
171
- return html`<a
172
- class=${classMap(cssClasses)}
173
- id="button"
174
- href=${this.href}
175
- target=${this.target}
176
- tabindex=${this.disabled ? '-1' : '0'}
177
- @click=${this.__dispatchClick}
178
- @mousedown=${this.__handlePress}
179
- @keydown=${this.__handlePress}
180
- @keyup=${this.__handlePress}
181
- role="button"
182
-
183
- aria-describedby=${ifDefined(this.softDisabled ? BaseButton.DISABLED_REASON_ID : undefined)}
184
- ?aria-disabled=${this.softDisabled}
171
+ } else {
172
+ cssClasses['native-link'] = true;
173
+ return html`<a
174
+ class=${classMap(cssClasses)}
175
+ id="button"
176
+ href=${this.href}
177
+ target=${this.target}
178
+ tabindex=${this.disabled ? '-1' : '0'}
179
+ @click=${this.__dispatchClick}
180
+ @mousedown=${this.__handlePress}
181
+ @keydown=${this.__handlePress}
182
+ @keyup=${this.__handlePress}
183
+ role="button"
184
+
185
+ aria-describedby=${ifDefined(this.softDisabled ? BaseButton.DISABLED_REASON_ID : undefined)}
186
+ ?aria-disabled=${this.softDisabled}
185
187
 
186
- ${spread(this.configAria)}
187
- >
188
- ${this.renderButtonContent()}
189
- </a>
190
- ${this.__renderTooltip()}`;
188
+ ${spread(this.configAria)}
189
+ >
190
+ ${this.renderButtonContent()}
191
+ </a>
192
+ ${this.__renderTooltip()}`;
193
+ }
191
194
  }
192
195
 
193
196
  renderButtonContent() {
@@ -12,8 +12,22 @@
12
12
  }
13
13
 
14
14
  .canvas-wrapper {
15
+ position: relative;
15
16
  background: var(--canvas-background);
16
- border-radius: var(--shape-corner-medium);
17
+ }
18
+
19
+ .canvas {
20
+ display: block;
21
+ }
22
+
23
+ .canvas-background,
24
+ .canvas-shapes {
25
+ position: absolute;
26
+ inset: 0;
27
+ }
28
+
29
+ .canvas-background {
30
+ pointer-events: none;
17
31
  }
18
32
 
19
33
  #canvas-background circle {
@@ -22,16 +36,14 @@
22
36
 
23
37
  #endarrow polyline {
24
38
  fill: none;
25
- stroke: var(--canvas-arrow-color);
39
+ stroke: context-stroke;
26
40
  vector-effect: non-scaling-stroke;
27
41
  stroke-width: 2;
42
+ stroke-linejoin: round;
43
+ stroke-linecap: round;
28
44
  }
29
45
 
30
46
  .line {
31
- &.no-color {
32
- stroke: var(--canvas-line-color);
33
- }
34
-
35
47
  &.variant-dashed {
36
48
  stroke-dasharray: 6 6;
37
49
  }
@@ -61,6 +61,9 @@ export type CanvasShape =
61
61
  | CanvasLineShape
62
62
  | CanvasConnectorShape;
63
63
 
64
+ const GRID_GAP = 10;
65
+ const GRID_DOT_RADIUS = 1;
66
+
64
67
  interface CanvasBounds {
65
68
  x: number;
66
69
  y: number;
@@ -68,6 +71,20 @@ interface CanvasBounds {
68
71
  height: number;
69
72
  }
70
73
 
74
+ interface CanvasExtents {
75
+ minX: number;
76
+ minY: number;
77
+ maxX: number;
78
+ maxY: number;
79
+ }
80
+
81
+ interface CanvasViewBox {
82
+ x: number;
83
+ y: number;
84
+ width: number;
85
+ height: number;
86
+ }
87
+
71
88
  /**
72
89
  * @label Canvas
73
90
  * @tag wc-canvas
@@ -118,10 +135,6 @@ export class Canvas extends LitElement {
118
135
  @property({ type: String })
119
136
  viewbox?: string;
120
137
 
121
- private unitSize: number = 1;
122
-
123
- private gap: number = this.unitSize * 10;
124
-
125
138
  private static getNextPoint(
126
139
  point: CanvasPoint,
127
140
  direction: CanvasDirection,
@@ -134,30 +147,33 @@ export class Canvas extends LitElement {
134
147
  return { x: point.x, y: point.y };
135
148
  }
136
149
 
137
- private static updateComputationArea(
138
- point: CanvasPoint,
139
- area: CanvasBounds,
140
- ): CanvasBounds {
141
- const nextArea = { ...area };
142
- if (point.x > nextArea.width) nextArea.width = point.x;
143
- else if (point.x < nextArea.x) nextArea.x = point.x;
144
- if (point.y > nextArea.height) nextArea.height = point.y;
145
- else if (point.y < nextArea.y) nextArea.y = point.y;
146
- return nextArea;
150
+ private static updateExtents(
151
+ extents: CanvasExtents,
152
+ x: number,
153
+ y: number,
154
+ ) {
155
+ if (x < extents.minX) extents.minX = x;
156
+ if (x > extents.maxX) extents.maxX = x;
157
+ if (y < extents.minY) extents.minY = y;
158
+ if (y > extents.maxY) extents.maxY = y;
147
159
  }
148
160
 
149
161
  private static getStrokeVariantClasses(variant?: CanvasStrokeVariant) {
150
162
  return {
151
163
  line: true,
152
- 'no-color': false,
153
164
  'variant-dashed': variant === 'dashed' || variant === 'animated-dashed',
154
165
  'variant-animated-dashed': variant === 'animated-dashed',
155
166
  };
156
167
  }
157
168
 
158
169
  private computeShapes(initialBounds: CanvasBounds) {
159
- const dotRadius = this.unitSize;
160
- let computedViewbox = { ...initialBounds };
170
+ // Track world-space bounds (grid units) as shapes are processed.
171
+ const extents: CanvasExtents = {
172
+ minX: initialBounds.x,
173
+ minY: initialBounds.y,
174
+ maxX: initialBounds.x + initialBounds.width,
175
+ maxY: initialBounds.y + initialBounds.height,
176
+ };
161
177
 
162
178
  const shapes = this.shapes.map(shape => {
163
179
  switch (shape.type) {
@@ -165,19 +181,14 @@ export class Canvas extends LitElement {
165
181
  const r = shape.radius || 1;
166
182
  const cx = shape.x || 0;
167
183
  const cy = shape.y || 0;
168
- if (cx + Math.ceil(r) > computedViewbox.width)
169
- computedViewbox.width = cx + Math.ceil(r);
170
- if (cx - Math.ceil(r) < computedViewbox.x)
171
- computedViewbox.x = cx - Math.ceil(r);
172
- if (cy + Math.ceil(r) > computedViewbox.height)
173
- computedViewbox.height = cy + Math.ceil(r);
174
- if (cy - Math.ceil(r) < computedViewbox.y)
175
- computedViewbox.y = cy - Math.ceil(r);
184
+ Canvas.updateExtents(extents, cx - r, cy - r);
185
+ Canvas.updateExtents(extents, cx + r, cy + r);
176
186
 
187
+ // Convert from grid units to SVG pixels using the fixed gap.
177
188
  return svg`<circle
178
- cx=${cx * this.gap + dotRadius}
179
- cy=${cy * this.gap + dotRadius}
180
- r=${r * this.gap}
189
+ cx=${cx * GRID_GAP + GRID_DOT_RADIUS}
190
+ cy=${cy * GRID_GAP + GRID_DOT_RADIUS}
191
+ r=${r * GRID_GAP}
181
192
  fill=${shape.color || 'var(--canvas-line-color, var(--color-on-surface))'}
182
193
  />`;
183
194
  }
@@ -186,27 +197,23 @@ export class Canvas extends LitElement {
186
197
  const h = shape.height || 1;
187
198
  const rx = shape.x || 0;
188
199
  const ry = shape.y || 0;
189
- if (rx + Math.ceil(w) > computedViewbox.width)
190
- computedViewbox.width = rx + Math.ceil(w);
191
- if (rx - Math.ceil(w) < computedViewbox.x)
192
- computedViewbox.x = rx - Math.ceil(w);
193
- if (ry + Math.ceil(h) > computedViewbox.height)
194
- computedViewbox.height = ry + Math.ceil(h);
195
- if (ry - Math.ceil(h) < computedViewbox.y)
196
- computedViewbox.y = ry - Math.ceil(h);
200
+ Canvas.updateExtents(extents, rx, ry);
201
+ Canvas.updateExtents(extents, rx + w, ry + h);
197
202
 
198
203
  return svg`<rect
199
- x=${rx * this.gap + dotRadius}
200
- y=${ry * this.gap}
201
- width=${w * this.gap + dotRadius}
202
- height=${h * this.gap + dotRadius}
204
+ x=${rx * GRID_GAP + GRID_DOT_RADIUS}
205
+ y=${ry * GRID_GAP}
206
+ width=${w * GRID_GAP + GRID_DOT_RADIUS}
207
+ height=${h * GRID_GAP + GRID_DOT_RADIUS}
203
208
  fill=${shape.color || 'var(--canvas-line-color, var(--color-on-surface))'}
204
209
  />`;
205
210
  }
206
211
  case 'line': {
207
212
  const start = shape.start || { x: 0, y: 0 };
208
213
  const end = shape.end || { x: 0, y: 0 };
209
- const pathString = `M${start.x * this.gap + dotRadius} ${start.y * this.gap + dotRadius} L${end.x * this.gap + dotRadius} ${end.y * this.gap + dotRadius}`;
214
+ Canvas.updateExtents(extents, start.x, start.y);
215
+ Canvas.updateExtents(extents, end.x, end.y);
216
+ const pathString = `M${start.x * GRID_GAP + GRID_DOT_RADIUS} ${start.y * GRID_GAP + GRID_DOT_RADIUS} L${end.x * GRID_GAP + GRID_DOT_RADIUS} ${end.y * GRID_GAP + GRID_DOT_RADIUS}`;
210
217
  const strokeColor =
211
218
  shape.color ||
212
219
  'var(--canvas-line-color, var(--color-on-surface))';
@@ -215,7 +222,6 @@ export class Canvas extends LitElement {
215
222
  class=${classMap({
216
223
  ...Canvas.getStrokeVariantClasses(shape.variant),
217
224
  clickable: !!shape.clickable,
218
- 'no-color': !shape.color,
219
225
  })}
220
226
  stroke-width="2"
221
227
  stroke-linecap="round"
@@ -229,19 +235,20 @@ export class Canvas extends LitElement {
229
235
  }
230
236
  case 'connector': {
231
237
  const start = shape.start || { x: 0, y: 0 };
232
- let pathString = `M${start.x * this.gap + dotRadius} ${start.y * this.gap + dotRadius}`;
238
+ let pathString = `M${start.x * GRID_GAP + GRID_DOT_RADIUS} ${start.y * GRID_GAP + GRID_DOT_RADIUS}`;
233
239
  let current = { ...start };
234
- computedViewbox = Canvas.updateComputationArea(current, computedViewbox);
240
+ Canvas.updateExtents(extents, current.x, current.y);
235
241
 
236
242
  const pathSegments = shape.path || [];
237
243
  for (let i = 0; i < pathSegments.length; i += 1) {
238
244
  const path = pathSegments[i];
239
245
 
240
246
  if (i === 0) {
247
+ // Move one unit first so curved corner joins don't overlap start.
241
248
  const point = Canvas.getNextPoint(current, path.direction, 1);
242
- pathString += ` L${point.x * this.gap + dotRadius} ${point.y * this.gap + dotRadius}`;
249
+ pathString += ` L${point.x * GRID_GAP + GRID_DOT_RADIUS} ${point.y * GRID_GAP + GRID_DOT_RADIUS}`;
243
250
  current = { ...point };
244
- computedViewbox = Canvas.updateComputationArea(current, computedViewbox);
251
+ Canvas.updateExtents(extents, current.x, current.y);
245
252
  }
246
253
 
247
254
  const point = Canvas.getNextPoint(
@@ -249,26 +256,28 @@ export class Canvas extends LitElement {
249
256
  path.direction,
250
257
  path.length - 2,
251
258
  );
252
- pathString += ` L${point.x * this.gap + dotRadius} ${point.y * this.gap + dotRadius}`;
259
+ pathString += ` L${point.x * GRID_GAP + GRID_DOT_RADIUS} ${point.y * GRID_GAP + GRID_DOT_RADIUS}`;
253
260
  current = { ...point };
254
- computedViewbox = Canvas.updateComputationArea(current, computedViewbox);
261
+ Canvas.updateExtents(extents, current.x, current.y);
255
262
 
256
263
  if (i === pathSegments.length - 1) {
257
264
  const endPoint = Canvas.getNextPoint(current, path.direction, 1);
258
- pathString += ` L${endPoint.x * this.gap + dotRadius} ${endPoint.y * this.gap + dotRadius}`;
265
+ pathString += ` L${endPoint.x * GRID_GAP + GRID_DOT_RADIUS} ${endPoint.y * GRID_GAP + GRID_DOT_RADIUS}`;
259
266
  current = { ...endPoint };
260
- computedViewbox = Canvas.updateComputationArea(current, computedViewbox);
267
+ Canvas.updateExtents(extents, current.x, current.y);
261
268
  } else {
262
269
  const nextPath = pathSegments[i + 1];
263
270
  const midPoint = Canvas.getNextPoint(current, path.direction, 1);
271
+ Canvas.updateExtents(extents, midPoint.x, midPoint.y);
264
272
  const nextPoint = Canvas.getNextPoint(
265
273
  midPoint,
266
274
  nextPath.direction,
267
275
  1,
268
276
  );
269
- pathString += ` Q ${midPoint.x * this.gap + dotRadius} ${midPoint.y * this.gap + dotRadius} ${nextPoint.x * this.gap + dotRadius} ${nextPoint.y * this.gap + dotRadius}`;
277
+ // Use a quadratic segment to round corners between directions.
278
+ pathString += ` Q ${midPoint.x * GRID_GAP + GRID_DOT_RADIUS} ${midPoint.y * GRID_GAP + GRID_DOT_RADIUS} ${nextPoint.x * GRID_GAP + GRID_DOT_RADIUS} ${nextPoint.y * GRID_GAP + GRID_DOT_RADIUS}`;
270
279
  current = { ...nextPoint };
271
- computedViewbox = Canvas.updateComputationArea(current, computedViewbox);
280
+ Canvas.updateExtents(extents, current.x, current.y);
272
281
  }
273
282
  }
274
283
 
@@ -280,7 +289,6 @@ export class Canvas extends LitElement {
280
289
  <path
281
290
  class=${classMap({
282
291
  ...Canvas.getStrokeVariantClasses(shape.variant),
283
- 'no-color': !shape.color,
284
292
  })}
285
293
  stroke-width="2"
286
294
  stroke-linecap="round"
@@ -306,19 +314,68 @@ export class Canvas extends LitElement {
306
314
  }
307
315
  });
308
316
 
309
- // Padding
310
- computedViewbox.x -= this.padding;
311
- computedViewbox.y -= this.padding;
312
- computedViewbox.width += this.padding;
313
- computedViewbox.height += this.padding;
314
- computedViewbox.width -= computedViewbox.x;
315
- computedViewbox.height -= computedViewbox.y;
317
+ // Expand bounds with padding so shapes are not flush to the edge.
318
+ const computedViewbox = {
319
+ x: extents.minX - this.padding,
320
+ y: extents.minY - this.padding,
321
+ width: Math.max(extents.maxX - extents.minX + this.padding * 2, 0),
322
+ height: Math.max(extents.maxY - extents.minY + this.padding * 2, 0),
323
+ };
316
324
 
317
325
  return { shapes, computedViewbox };
318
326
  }
319
327
 
328
+ private renderBackgroundSvg(computedViewBox: CanvasViewBox, svgViewBox: string) {
329
+ return html`
330
+ <svg
331
+ class="canvas canvas-background"
332
+ height="100%"
333
+ width="100%"
334
+ viewBox=${svgViewBox}
335
+ aria-hidden="true"
336
+ >
337
+ <defs>
338
+ <pattern
339
+ id="canvas-background"
340
+ patternUnits="userSpaceOnUse"
341
+ width=${GRID_GAP}
342
+ height=${GRID_GAP}
343
+ >
344
+ <circle cx="1" cy="1" r=${GRID_DOT_RADIUS} />
345
+ </pattern>
346
+ </defs>
347
+
348
+ <rect
349
+ x=${computedViewBox.x * GRID_GAP}
350
+ y=${computedViewBox.y * GRID_GAP}
351
+ width="100%"
352
+ height="100%"
353
+ fill="url(#canvas-background)"
354
+ />
355
+ </svg>
356
+ `;
357
+ }
358
+
359
+ private renderShapesSvg(shapes: unknown[], svgViewBox: string) {
360
+ return html`
361
+ <svg
362
+ class="canvas canvas-shapes"
363
+ height="100%"
364
+ width="100%"
365
+ viewBox=${svgViewBox}
366
+ >
367
+ <defs>
368
+ <marker id="endarrow" markerWidth="10" markerHeight="10" refX="5" refY="5" markerUnits="strokeWidth" orient="auto">
369
+ <polyline points="0 2, 5 5, 0 8"></polyline>
370
+ </marker>
371
+ </defs>
372
+
373
+ ${shapes}
374
+ </svg>
375
+ `;
376
+ }
377
+
320
378
  protected render() {
321
- const dotRadius = this.unitSize;
322
379
  let computedViewBox = { width: 0, height: 0, x: 0, y: 0 };
323
380
 
324
381
  const { shapes, computedViewbox } = this.computeShapes(computedViewBox);
@@ -334,57 +391,22 @@ export class Canvas extends LitElement {
334
391
  };
335
392
  }
336
393
 
394
+ // Zoom scales the outer viewport size while the SVG viewBox stays in world units.
337
395
  const wrapperWidth =
338
- (computedViewBox.width * this.gap + 2) * dotRadius * this.zoom;
396
+ (computedViewBox.width * GRID_GAP + 2) * GRID_DOT_RADIUS * this.zoom;
339
397
  const wrapperHeight =
340
- (computedViewBox.height * this.gap + 2) * dotRadius * this.zoom;
398
+ (computedViewBox.height * GRID_GAP + 2) * GRID_DOT_RADIUS * this.zoom;
341
399
 
342
- const svgViewBox = `${computedViewBox.x * this.gap} ${computedViewBox.y * this.gap} ${computedViewBox.width * this.gap + 2 * dotRadius} ${computedViewBox.height * this.gap + 2 * dotRadius}`;
400
+ // viewBox maps world-space extents into the internal SVG coordinate system.
401
+ const svgViewBox = `${computedViewBox.x * GRID_GAP} ${computedViewBox.y * GRID_GAP} ${computedViewBox.width * GRID_GAP + 2 * GRID_DOT_RADIUS} ${computedViewBox.height * GRID_GAP + 2 * GRID_DOT_RADIUS}`;
343
402
 
344
403
  return html`
345
404
  <div
346
405
  class="canvas-wrapper"
347
406
  style="width: ${wrapperWidth}px; height: ${wrapperHeight}px;"
348
407
  >
349
- <svg
350
- class="canvas"
351
- height="100%"
352
- width="100%"
353
- viewBox=${svgViewBox}
354
- >
355
- <defs>
356
- <pattern
357
- id="canvas-background"
358
- patternUnits="userSpaceOnUse"
359
- width=${this.gap}
360
- height=${this.gap}
361
- >
362
- <circle cx="1" cy="1" r=${dotRadius} />
363
- </pattern>
364
-
365
- <marker
366
- id="endarrow"
367
- markerWidth="15"
368
- markerHeight="22.5"
369
- refX="9"
370
- refY="15"
371
- markerUnits="userSpaceOnUse"
372
- orient="auto"
373
- >
374
- <polyline points="0 22.5, 7.5 15, 0 7.5"></polyline>
375
- </marker>
376
- </defs>
377
-
378
- <rect
379
- x=${computedViewBox.x * this.gap}
380
- y=${computedViewBox.y * this.gap}
381
- width="100%"
382
- height="100%"
383
- fill="url(#canvas-background)"
384
- />
385
-
386
- ${shapes}
387
- </svg>
408
+ ${this.renderBackgroundSvg(computedViewBox, svgViewBox)}
409
+ ${this.renderShapesSvg(shapes, svgViewBox)}
388
410
  </div>
389
411
  `;
390
412
  }
package/src/card/card.ts CHANGED
@@ -189,7 +189,7 @@ export class Card extends BaseHyperlinkMixin(LitElement) {
189
189
  tabindex=${this.#tabindex}
190
190
  href=${this.href}
191
191
  target=${this.target}
192
- @click=${this.__dispatchClickWithThrottle}
192
+ @click=${this.__dispatchClickWithThrottle}
193
193
  @mousedown=${this.__handlePress}
194
194
  @keydown=${this.__handlePress}
195
195
  @keyup=${this.__handlePress}