@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.136 → 2.0.0-next.137
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.
- package/bundle/openbridge-webcomponents.bundle.js +11434 -10949
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +784 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.css.js +12 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.css.js.map +1 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.d.ts +33 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.d.ts.map +1 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.js +58 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.js.map +1 -0
- package/dist/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.d.ts +77 -0
- package/dist/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.d.ts.map +1 -0
- package/dist/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.js +74 -0
- package/dist/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.js.map +1 -0
- package/dist/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.d.ts +74 -0
- package/dist/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.d.ts.map +1 -0
- package/dist/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.js +60 -0
- package/dist/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.js.map +1 -0
- package/dist/automation/shuffle-button/shuffle-button-base.d.ts +67 -0
- package/dist/automation/shuffle-button/shuffle-button-base.d.ts.map +1 -0
- package/dist/automation/shuffle-button/shuffle-button-base.js +126 -0
- package/dist/automation/shuffle-button/shuffle-button-base.js.map +1 -0
- package/dist/automation/shuffle-button/shuffle-button.css.js +219 -0
- package/dist/automation/shuffle-button/shuffle-button.css.js.map +1 -0
- package/dist/automation/shuffle-button/shuffle-layout.d.ts +9 -0
- package/dist/automation/shuffle-button/shuffle-layout.d.ts.map +1 -0
- package/dist/automation/shuffle-button/shuffle-layout.js +16 -0
- package/dist/automation/shuffle-button/shuffle-layout.js.map +1 -0
- package/package.json +1 -1
- package/src/automation/hydraulic-check-valve/hydraulic-check-valve.css +3 -0
- package/src/automation/hydraulic-check-valve/hydraulic-check-valve.stories.ts +18 -0
- package/src/automation/hydraulic-check-valve/hydraulic-check-valve.ts +60 -0
- package/src/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.stories.ts +72 -0
- package/src/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.ts +108 -0
- package/src/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.stories.ts +60 -0
- package/src/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.ts +101 -0
- package/src/automation/shuffle-button/shuffle-button-base.ts +170 -0
- package/src/automation/shuffle-button/shuffle-button.css +136 -0
- package/src/automation/shuffle-button/shuffle-layout.spec.ts +44 -0
- package/src/automation/shuffle-button/shuffle-layout.ts +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shuffle-button-base.js","sources":["../../../src/automation/shuffle-button/shuffle-button-base.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport type {PropertyValues, TemplateResult} from 'lit';\nimport {property, state} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport componentStyle from './shuffle-button.css?inline';\nimport {\n clampPosition,\n shuffleSlotCount,\n shuffleWindowOffset,\n} from './shuffle-layout.js';\n\n/**\n * Detail payload for the `position-selected` event dispatched by\n * shuffle-button components. `position` is the zero-based position the user\n * requested.\n */\nexport interface PositionSelectedDetail {\n position: number;\n}\n\n/**\n * The `position-selected` event dispatched by shuffle-button components.\n */\nexport type PositionSelectedEvent = CustomEvent<PositionSelectedDetail>;\n\n/**\n * Base class for shuffle-button selectors: a control whose selected thumb\n * always occupies the fixed center slot of a (2·n−1)-slot row (or column when\n * `vertical`). Option thumbs keep their logical order and redistribute to\n * either side of the selected thumb; empty spacer slots absorb the remaining\n * length so the total size never changes.\n *\n * ## Controlled selection\n * Clicking an option or pressing an arrow key only fires `position-selected`.\n * The host application sets `selectedPosition` once the device confirms the\n * change, so the control never shows a position the device has not reached.\n *\n * ## Keyboard\n * Follows the WAI-ARIA radio group pattern\n * (https://www.w3.org/WAI/ARIA/apg/patterns/radio/): `role=\"radiogroup\"` with\n * one `role=\"radio\"` thumb per position, a single tab stop on the selected\n * thumb, and Left/Up and Right/Down moving to the previous/next position with\n * wrap-around. Departures: arrow keys request the position rather than moving\n * the checked state (controlled selection above), and focus follows the thumb\n * only once the host confirms it. Space/Enter on a focused thumb request it\n * through the native button click. Home/End are out of scope.\n *\n * Subclasses define `positionCount` and `renderPositionIcon()` and carry the\n * `@fires position-selected` tag: the manifest and the framework wrappers read\n * events from the registered element, not from this base.\n *\n * Not declared `abstract`: the wrapper generators wrap every `LitElement`\n * subclass and pass its constructor as a concrete `Constructor<T>`, so the\n * default implementations below stand in for abstract members (same as\n * `ObcAbstractAutomationButton`).\n *\n * @property selectedPosition - Zero-based index of the currently selected position. Out-of-range values are clamped.\n * @property vertical - Lays the control out vertically: positions stack top to bottom and the position symbols rotate 90° counter-clockwise to match a vertical flow path.\n * @property ariaLabel - Accessible name for the radio group (the control is icon-only). Concrete components override the default with a device-specific name.\n */\nexport class ObcShuffleButtonBase extends LitElement {\n @property({type: Number}) selectedPosition = 1;\n\n @property({type: Boolean}) vertical = false;\n\n @property({type: String}) override ariaLabel = 'Position selector';\n\n @state() private suppressHover = false;\n\n protected get positionCount(): number {\n return 1;\n }\n\n protected renderPositionIcon(_position: number): TemplateResult {\n return html``;\n }\n\n override render() {\n const count = this.positionCount;\n const selected = clampPosition(count, this.selectedPosition);\n return html`\n <div\n class=${classMap({shuffle: true, vertical: this.vertical})}\n role=\"radiogroup\"\n aria-label=${this.ariaLabel}\n aria-orientation=${this.vertical ? 'vertical' : 'horizontal'}\n style=\"--_shuffle-slot-count: ${shuffleSlotCount(\n count\n )}; --_shuffle-window-offset: ${shuffleWindowOffset(\n count,\n selected\n )};${this.suppressHover ? ' --obc-can-hover: 0;' : ''}\"\n @keydown=${this.handleKeydown}\n @pointermove=${this.restoreHover}\n >\n <div class=\"window\">\n <div class=\"track\"></div>\n ${Array.from({length: count}, (_, position) =>\n this.renderThumb(position, selected)\n )}\n </div>\n </div>\n `;\n }\n\n private renderThumb(position: number, selected: number) {\n const isSelected = position === selected;\n return html`\n <button\n class=${classMap({thumb: true, selected: isSelected})}\n type=\"button\"\n role=\"radio\"\n aria-checked=${isSelected}\n tabindex=${isSelected ? 0 : -1}\n @click=${() => this.requestPosition(position)}\n >\n <div class=\"visible-wrapper\">\n <div class=\"icon-container\">${this.renderPositionIcon(position)}</div>\n </div>\n </button>\n `;\n }\n\n private requestPosition(position: number) {\n if (position === clampPosition(this.positionCount, this.selectedPosition)) {\n return;\n }\n // Browsers keep :hover on the thumb that shuffles away from under a\n // stationary pointer; mute hover feedback until the pointer really moves.\n this.suppressHover = true;\n const event: PositionSelectedEvent = new CustomEvent('position-selected', {\n detail: {position},\n bubbles: true,\n composed: true,\n });\n this.dispatchEvent(event);\n }\n\n private restoreHover() {\n this.suppressHover = false;\n }\n\n private handleKeydown(event: KeyboardEvent) {\n let delta: number;\n if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {\n delta = 1;\n } else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {\n delta = -1;\n } else {\n return;\n }\n event.preventDefault();\n const count = this.positionCount;\n const selected = clampPosition(count, this.selectedPosition);\n this.requestPosition((selected + delta + count) % count);\n }\n\n protected override updated(changed: PropertyValues) {\n if (\n changed.has('selectedPosition') &&\n this.shadowRoot?.activeElement instanceof HTMLElement\n ) {\n this.shadowRoot\n .querySelector<HTMLButtonElement>('button.thumb.selected')\n ?.focus();\n }\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { css } from "lit";
|
|
2
|
+
const componentStyle = css`* {
|
|
3
|
+
-webkit-tap-highlight-color: transparent;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
:host {
|
|
7
|
+
display: inline-block;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* ---- Slot grid ----
|
|
11
|
+
* The box is (2n-1) touch-target slots; the selected thumb always sits in the
|
|
12
|
+
* center slot, so the box never changes size with the selection. */
|
|
13
|
+
|
|
14
|
+
.shuffle {
|
|
15
|
+
--shuffle-slot-size: var(--global-size-spacing-touch-target-min);
|
|
16
|
+
--_shuffle-slot-count: 1;
|
|
17
|
+
--_shuffle-window-offset: 0;
|
|
18
|
+
position: relative; /* containing block for the sliding .window */
|
|
19
|
+
width: calc(var(--_shuffle-slot-count) * var(--shuffle-slot-size));
|
|
20
|
+
height: var(--shuffle-slot-size);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.shuffle.vertical {
|
|
24
|
+
width: var(--shuffle-slot-size);
|
|
25
|
+
height: calc(var(--_shuffle-slot-count) * var(--shuffle-slot-size));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* The window holds the n thumbs in logical order and slides by whole slots so
|
|
29
|
+
* the selected one lands in the center; the box above stays put. */
|
|
30
|
+
|
|
31
|
+
.window {
|
|
32
|
+
position: absolute; /* slides inside the fixed-size .shuffle box */
|
|
33
|
+
top: 0;
|
|
34
|
+
left: 0;
|
|
35
|
+
display: flex;
|
|
36
|
+
transform: translateX(
|
|
37
|
+
calc(var(--_shuffle-window-offset) * var(--shuffle-slot-size))
|
|
38
|
+
);
|
|
39
|
+
transition: transform 100ms ease-out; /* TODO(designer): Figma is WIP and specifies no motion */
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.shuffle.vertical .window {
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
transform: translateY(
|
|
45
|
+
calc(var(--_shuffle-window-offset) * var(--shuffle-slot-size))
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@media (prefers-reduced-motion: reduce) {
|
|
50
|
+
.window {
|
|
51
|
+
transition: none;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* The track is inset to the visual target height so it aligns with the thumbs'
|
|
56
|
+
* visible wrappers, not with the touch slots. */
|
|
57
|
+
|
|
58
|
+
.track {
|
|
59
|
+
border-color: var(--indent-enabled-border-color);
|
|
60
|
+
background-color: var(--indent-enabled-background-color);
|
|
61
|
+
border-width: 1px;
|
|
62
|
+
border-style: solid;
|
|
63
|
+
--base-border-color: var(--indent-enabled-border-color);
|
|
64
|
+
--base-background-color: var(--indent-enabled-background-color);
|
|
65
|
+
position: absolute;
|
|
66
|
+
inset: calc(
|
|
67
|
+
(
|
|
68
|
+
var(--shuffle-slot-size) -
|
|
69
|
+
var(--global-size-spacing-visual-target-min)
|
|
70
|
+
) /
|
|
71
|
+
2
|
|
72
|
+
)
|
|
73
|
+
0;
|
|
74
|
+
border-radius: var(--global-border-radius-border-radius-base);
|
|
75
|
+
box-sizing: border-box; /* the mixin border must not grow the track past the slots */
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.shuffle.vertical .track {
|
|
79
|
+
inset: 0
|
|
80
|
+
calc(
|
|
81
|
+
(
|
|
82
|
+
var(--shuffle-slot-size) -
|
|
83
|
+
var(--global-size-spacing-visual-target-min)
|
|
84
|
+
) /
|
|
85
|
+
2
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ---- Thumbs ----
|
|
90
|
+
* Two-layer pattern: the button is the touch target and focus-ring layer, the
|
|
91
|
+
* .visible-wrapper is the visual target. */
|
|
92
|
+
|
|
93
|
+
.thumb {
|
|
94
|
+
position: relative;
|
|
95
|
+
width: var(--shuffle-slot-size);
|
|
96
|
+
height: var(--shuffle-slot-size);
|
|
97
|
+
display: flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
flex-shrink: 0; /* a slot never shrinks below the touch target */
|
|
101
|
+
padding: 0;
|
|
102
|
+
margin: 0;
|
|
103
|
+
border: none;
|
|
104
|
+
background: none;
|
|
105
|
+
cursor: pointer;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
button.thumb {
|
|
109
|
+
cursor: pointer;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
button.thumb:focus {
|
|
113
|
+
outline: none;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
button.thumb .visible-wrapper {
|
|
117
|
+
border-color: var(--flat-enabled-border-color);
|
|
118
|
+
background-color: var(--flat-enabled-background-color);
|
|
119
|
+
border-width: 1px;
|
|
120
|
+
border-style: solid;
|
|
121
|
+
cursor: pointer;
|
|
122
|
+
--base-border-color: var(--flat-enabled-border-color);
|
|
123
|
+
--base-background-color: var(--flat-enabled-background-color);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
button.thumb.activated .visible-wrapper {
|
|
127
|
+
border-color: var(--flat-activated-border-color);
|
|
128
|
+
background-color: var(--flat-activated-background-color);
|
|
129
|
+
--base-border-color: var(--flat-activated-border-color);
|
|
130
|
+
--base-background-color: var(--flat-activated-background-color);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@media (hover:hover) {
|
|
134
|
+
|
|
135
|
+
button.thumb:hover .visible-wrapper {
|
|
136
|
+
border-color: color-mix(in srgb, var(--flat-hover-border-color) calc(var(--obc-can-hover) * 100%), var(--base-border-color));
|
|
137
|
+
background-color: color-mix(in srgb, var(--flat-hover-background-color) calc(var(--obc-can-hover) * 100%), var(--base-background-color));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
button.thumb:active .visible-wrapper {
|
|
142
|
+
border-color: var(--flat-pressed-border-color);
|
|
143
|
+
background-color: var(--flat-pressed-background-color);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
button.thumb:focus-visible .visible-wrapper {
|
|
147
|
+
outline-color: var(--border-focus-color);
|
|
148
|
+
outline-width: var(--global-size-spacing-border-weight-focusframe);
|
|
149
|
+
outline-style: solid;
|
|
150
|
+
border-color: var(--container-global-color);
|
|
151
|
+
z-index: 1;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
button.thumb:disabled .visible-wrapper {
|
|
155
|
+
border-color: var(--flat-disabled-border-color);
|
|
156
|
+
background-color: var(--flat-disabled-background-color);
|
|
157
|
+
cursor: not-allowed;
|
|
158
|
+
color: var(--on-flat-disabled-color) !important;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
button.thumb.disabled .visible-wrapper {
|
|
162
|
+
border-color: var(--flat-disabled-border-color);
|
|
163
|
+
background-color: var(--flat-disabled-background-color);
|
|
164
|
+
cursor: not-allowed;
|
|
165
|
+
color: var(--on-flat-disabled-color) !important;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
button.thumb:disabled {
|
|
169
|
+
cursor: not-allowed;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
button.thumb.disabled {
|
|
173
|
+
cursor: not-allowed;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.visible-wrapper {
|
|
177
|
+
display: flex;
|
|
178
|
+
align-items: center;
|
|
179
|
+
justify-content: center;
|
|
180
|
+
width: 100%;
|
|
181
|
+
height: var(--global-size-spacing-visual-target-min);
|
|
182
|
+
box-sizing: border-box;
|
|
183
|
+
border-radius: var(--global-border-radius-border-radius-base);
|
|
184
|
+
color: var(--automation-device-secondary-color);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.thumb.selected {
|
|
188
|
+
cursor: default; /* clicking the selected position is a no-op */
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.thumb.selected .visible-wrapper {
|
|
192
|
+
background-color: var(--automation-pipe-primary-color);
|
|
193
|
+
border: 1px solid var(--automation-pipe-tertiary-color);
|
|
194
|
+
color: var(--automation-device-tertiary-color);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.shuffle.vertical .visible-wrapper {
|
|
198
|
+
width: var(--global-size-spacing-visual-target-min);
|
|
199
|
+
height: 100%;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.icon-container {
|
|
203
|
+
width: var(--global-size-spacing-icon-icon-size-regular);
|
|
204
|
+
height: var(--global-size-spacing-icon-icon-size-regular);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.shuffle.vertical .icon-container {
|
|
208
|
+
transform: rotate(-90deg); /* symbols are drawn for horizontal flow */
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.icon-container > * {
|
|
212
|
+
width: 100%;
|
|
213
|
+
height: 100%;
|
|
214
|
+
}
|
|
215
|
+
`;
|
|
216
|
+
export {
|
|
217
|
+
componentStyle as default
|
|
218
|
+
};
|
|
219
|
+
//# sourceMappingURL=shuffle-button.css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shuffle-button.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure layout math for the shuffle-button mechanism: a selector whose selected
|
|
3
|
+
* thumb always occupies the fixed center slot of a (2n-1)-slot row while the
|
|
4
|
+
* remaining option thumbs keep their logical order on either side.
|
|
5
|
+
*/
|
|
6
|
+
export declare function clampPosition(positionCount: number, position: number): number;
|
|
7
|
+
export declare function shuffleSlotCount(positionCount: number): number;
|
|
8
|
+
export declare function shuffleWindowOffset(positionCount: number, selectedPosition: number): number;
|
|
9
|
+
//# sourceMappingURL=shuffle-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shuffle-layout.d.ts","sourceRoot":"","sources":["../../../src/automation/shuffle-button/shuffle-layout.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG7E;AAED,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAER"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function clampPosition(positionCount, position) {
|
|
2
|
+
const rounded = Number.isNaN(position) ? 0 : Math.round(position);
|
|
3
|
+
return Math.min(Math.max(rounded, 0), positionCount - 1);
|
|
4
|
+
}
|
|
5
|
+
function shuffleSlotCount(positionCount) {
|
|
6
|
+
return 2 * positionCount - 1;
|
|
7
|
+
}
|
|
8
|
+
function shuffleWindowOffset(positionCount, selectedPosition) {
|
|
9
|
+
return positionCount - 1 - clampPosition(positionCount, selectedPosition);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
clampPosition,
|
|
13
|
+
shuffleSlotCount,
|
|
14
|
+
shuffleWindowOffset
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=shuffle-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shuffle-layout.js","sources":["../../../src/automation/shuffle-button/shuffle-layout.ts"],"sourcesContent":["/**\n * Pure layout math for the shuffle-button mechanism: a selector whose selected\n * thumb always occupies the fixed center slot of a (2n-1)-slot row while the\n * remaining option thumbs keep their logical order on either side.\n */\n\nexport function clampPosition(positionCount: number, position: number): number {\n const rounded = Number.isNaN(position) ? 0 : Math.round(position);\n return Math.min(Math.max(rounded, 0), positionCount - 1);\n}\n\nexport function shuffleSlotCount(positionCount: number): number {\n return 2 * positionCount - 1;\n}\n\nexport function shuffleWindowOffset(\n positionCount: number,\n selectedPosition: number\n): number {\n return positionCount - 1 - clampPosition(positionCount, selectedPosition);\n}\n"],"names":[],"mappings":"AAMO,SAAS,cAAc,eAAuB,UAA0B;AAC7E,QAAM,UAAU,OAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,MAAM,QAAQ;AAChE,SAAO,KAAK,IAAI,KAAK,IAAI,SAAS,CAAC,GAAG,gBAAgB,CAAC;AACzD;AAEO,SAAS,iBAAiB,eAA+B;AAC9D,SAAO,IAAI,gBAAgB;AAC7B;AAEO,SAAS,oBACd,eACA,kBACQ;AACR,SAAO,gBAAgB,IAAI,cAAc,eAAe,gBAAgB;AAC1E;"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
|
+
import {ObcHydraulicCheckValve} from './hydraulic-check-valve.js';
|
|
3
|
+
import './hydraulic-check-valve.js';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof ObcHydraulicCheckValve> = {
|
|
6
|
+
title: 'Automation/Hydraulic Valves/Check Valve',
|
|
7
|
+
tags: ['autodocs', '6.1', 'experimental'],
|
|
8
|
+
component: 'obc-hydraulic-check-valve',
|
|
9
|
+
} satisfies Meta<ObcHydraulicCheckValve>;
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<ObcHydraulicCheckValve>;
|
|
13
|
+
|
|
14
|
+
export const Default: Story = {};
|
|
15
|
+
|
|
16
|
+
export const Vertical: Story = {
|
|
17
|
+
args: {vertical: true},
|
|
18
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {LitElement, html, unsafeCSS} from 'lit';
|
|
2
|
+
import {property} from 'lit/decorators.js';
|
|
3
|
+
import {classMap} from 'lit/directives/class-map.js';
|
|
4
|
+
import {customElement} from '../../decorator.js';
|
|
5
|
+
import sharedStyle from '../shuffle-button/shuffle-button.css?inline';
|
|
6
|
+
import componentStyle from './hydraulic-check-valve.css?inline';
|
|
7
|
+
import '../../icons/icon-hydraulic-13.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `<obc-hydraulic-check-valve>` – Static check valve symbol.
|
|
11
|
+
*
|
|
12
|
+
* Renders the check valve symbol in the same thumb-on-track visual style as
|
|
13
|
+
* the position-selector valve components, sized to a single slot (48px at
|
|
14
|
+
* regular size). A check valve has no selectable positions, so the component
|
|
15
|
+
* is display-only and not focusable.
|
|
16
|
+
*
|
|
17
|
+
* ## Usage Guidelines
|
|
18
|
+
* Use alongside `<obc-hydraulic-valve-4-3>` and `<obc-hydraulic-valve-x-2>`
|
|
19
|
+
* for consistent styling of valves without switchable positions.
|
|
20
|
+
*
|
|
21
|
+
* @experimental
|
|
22
|
+
*
|
|
23
|
+
* @property ariaLabel - Accessible name for the symbol.
|
|
24
|
+
* @property vertical - Rotates the symbol 90° counter-clockwise to match a vertical flow path.
|
|
25
|
+
*/
|
|
26
|
+
@customElement('obc-hydraulic-check-valve')
|
|
27
|
+
export class ObcHydraulicCheckValve extends LitElement {
|
|
28
|
+
@property({type: String}) override ariaLabel = 'Check valve';
|
|
29
|
+
|
|
30
|
+
@property({type: Boolean}) vertical = false;
|
|
31
|
+
|
|
32
|
+
override render() {
|
|
33
|
+
return html`
|
|
34
|
+
<div
|
|
35
|
+
class=${classMap({shuffle: true, vertical: this.vertical})}
|
|
36
|
+
role="img"
|
|
37
|
+
aria-label=${this.ariaLabel}
|
|
38
|
+
>
|
|
39
|
+
<div class="window">
|
|
40
|
+
<div class="track"></div>
|
|
41
|
+
<div class="thumb selected">
|
|
42
|
+
<div class="visible-wrapper">
|
|
43
|
+
<div class="icon-container">
|
|
44
|
+
<obi-hydraulic-13></obi-hydraulic-13>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static override styles = [unsafeCSS(sharedStyle), unsafeCSS(componentStyle)];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
declare global {
|
|
57
|
+
interface HTMLElementTagNameMap {
|
|
58
|
+
'obc-hydraulic-check-valve': ObcHydraulicCheckValve;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
|
+
import {html} from 'lit';
|
|
3
|
+
import {
|
|
4
|
+
HydraulicValve43Type,
|
|
5
|
+
ObcHydraulicValve43,
|
|
6
|
+
} from './hydraulic-valve-4-3.js';
|
|
7
|
+
import './hydraulic-valve-4-3.js';
|
|
8
|
+
import type {PositionSelectedEvent} from '../shuffle-button/shuffle-button-base.js';
|
|
9
|
+
|
|
10
|
+
const meta: Meta<typeof ObcHydraulicValve43> = {
|
|
11
|
+
title: 'Automation/Hydraulic Valves/Valve 4-3',
|
|
12
|
+
tags: ['autodocs', '6.1', 'experimental'],
|
|
13
|
+
component: 'obc-hydraulic-valve-4-3',
|
|
14
|
+
args: {
|
|
15
|
+
type: HydraulicValve43Type.One,
|
|
16
|
+
selectedPosition: 1,
|
|
17
|
+
vertical: false,
|
|
18
|
+
},
|
|
19
|
+
argTypes: {
|
|
20
|
+
type: {
|
|
21
|
+
control: {type: 'select'},
|
|
22
|
+
options: Object.values(HydraulicValve43Type),
|
|
23
|
+
},
|
|
24
|
+
selectedPosition: {
|
|
25
|
+
control: {type: 'number', min: 0, max: 2, step: 1},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
render: (args) => html`
|
|
29
|
+
<obc-hydraulic-valve-4-3
|
|
30
|
+
type=${args.type}
|
|
31
|
+
.selectedPosition=${args.selectedPosition}
|
|
32
|
+
?vertical=${args.vertical}
|
|
33
|
+
@position-selected=${(event: PositionSelectedEvent) => {
|
|
34
|
+
(event.target as ObcHydraulicValve43).selectedPosition =
|
|
35
|
+
event.detail.position;
|
|
36
|
+
}}
|
|
37
|
+
></obc-hydraulic-valve-4-3>
|
|
38
|
+
`,
|
|
39
|
+
} satisfies Meta<ObcHydraulicValve43>;
|
|
40
|
+
|
|
41
|
+
export default meta;
|
|
42
|
+
type Story = StoryObj<ObcHydraulicValve43>;
|
|
43
|
+
|
|
44
|
+
export const Default: Story = {};
|
|
45
|
+
|
|
46
|
+
export const Type2: Story = {
|
|
47
|
+
args: {type: HydraulicValve43Type.Two},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const Type3: Story = {
|
|
51
|
+
args: {type: HydraulicValve43Type.Three},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Type4: Story = {
|
|
55
|
+
args: {type: HydraulicValve43Type.Four},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Type5: Story = {
|
|
59
|
+
args: {type: HydraulicValve43Type.Five},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const PositionLeft: Story = {
|
|
63
|
+
args: {selectedPosition: 0},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const PositionRight: Story = {
|
|
67
|
+
args: {selectedPosition: 2},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const Vertical: Story = {
|
|
71
|
+
args: {vertical: true},
|
|
72
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {html} from 'lit';
|
|
2
|
+
import type {TemplateResult} from 'lit';
|
|
3
|
+
import {property} from 'lit/decorators.js';
|
|
4
|
+
import {customElement} from '../../decorator.js';
|
|
5
|
+
import {ObcShuffleButtonBase} from '../shuffle-button/shuffle-button-base.js';
|
|
6
|
+
import '../../icons/icon-hydraulic-01.js';
|
|
7
|
+
import '../../icons/icon-hydraulic-02.js';
|
|
8
|
+
import '../../icons/icon-hydraulic-05.js';
|
|
9
|
+
import '../../icons/icon-hydraulic-06.js';
|
|
10
|
+
import '../../icons/icon-hydraulic-07.js';
|
|
11
|
+
import '../../icons/icon-hydraulic-08.js';
|
|
12
|
+
import '../../icons/icon-hydraulic-16.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Detail payload for the `position-selected` event: the zero-based position
|
|
16
|
+
* the user requested (0 = left, 1 = center, 2 = right).
|
|
17
|
+
*
|
|
18
|
+
* Declared here rather than imported from the base: the wrapper generators
|
|
19
|
+
* resolve event types in the component's own module only.
|
|
20
|
+
*/
|
|
21
|
+
export interface PositionSelectedDetail {
|
|
22
|
+
position: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Center-position symbol variant of `<obc-hydraulic-valve-4-3>`.
|
|
27
|
+
* Each value maps to a different center (neutral) position symbol.
|
|
28
|
+
*/
|
|
29
|
+
export enum HydraulicValve43Type {
|
|
30
|
+
One = '1',
|
|
31
|
+
Two = '2',
|
|
32
|
+
Three = '3',
|
|
33
|
+
Four = '4',
|
|
34
|
+
Five = '5',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `<obc-hydraulic-valve-4-3>` – Position selector symbol for a 4/3 directional valve.
|
|
39
|
+
*
|
|
40
|
+
* Shows the valve's three positions as icon thumbs on a shared track. The
|
|
41
|
+
* selected position always occupies the fixed center slot; the other position
|
|
42
|
+
* thumbs keep their logical order and shift to either side, so the component's
|
|
43
|
+
* total width never changes (five 48px slots at regular size).
|
|
44
|
+
*
|
|
45
|
+
* ## Features / Variants
|
|
46
|
+
* - `type` selects the center-position symbol (five variants).
|
|
47
|
+
* - `vertical` stacks the positions top to bottom and rotates the symbols to
|
|
48
|
+
* match a vertical flow path.
|
|
49
|
+
* - Controlled selection: clicking an option or pressing arrow keys fires
|
|
50
|
+
* `position-selected` with the requested position; the application updates
|
|
51
|
+
* `selectedPosition` once the change is confirmed.
|
|
52
|
+
* - Scales with the component size classes (`obc-component-size-*`).
|
|
53
|
+
*
|
|
54
|
+
* ## Usage Guidelines
|
|
55
|
+
* Use to display and command the position of a 4/3 directional valve. For
|
|
56
|
+
* two-position valves use `<obc-hydraulic-valve-x-2>`; for a static check
|
|
57
|
+
* valve symbol use `<obc-hydraulic-check-valve>`. Bind `selectedPosition` to
|
|
58
|
+
* the position the device reports, not to the last request, so the symbol
|
|
59
|
+
* never shows a position the valve has not reached.
|
|
60
|
+
*
|
|
61
|
+
* ## Events
|
|
62
|
+
* - `position-selected` – Fired when the user requests a position (click or
|
|
63
|
+
* arrow key). Detail: `{position: number}` (0 = left, 1 = center, 2 = right).
|
|
64
|
+
*
|
|
65
|
+
* @property type - Center-position symbol variant.
|
|
66
|
+
* @property ariaLabel - Accessible name for the control.
|
|
67
|
+
* @fires {CustomEvent<PositionSelectedDetail>} position-selected - Fired when the user requests a position (click or arrow key).
|
|
68
|
+
* @experimental
|
|
69
|
+
*/
|
|
70
|
+
@customElement('obc-hydraulic-valve-4-3')
|
|
71
|
+
export class ObcHydraulicValve43 extends ObcShuffleButtonBase {
|
|
72
|
+
@property({type: String}) type: HydraulicValve43Type =
|
|
73
|
+
HydraulicValve43Type.One;
|
|
74
|
+
|
|
75
|
+
@property({type: String}) override ariaLabel = 'Hydraulic 4/3 valve';
|
|
76
|
+
|
|
77
|
+
protected override get positionCount(): number {
|
|
78
|
+
return 3;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
protected override renderPositionIcon(position: number): TemplateResult {
|
|
82
|
+
if (position === 0) {
|
|
83
|
+
return html`<obi-hydraulic-02></obi-hydraulic-02>`;
|
|
84
|
+
}
|
|
85
|
+
if (position === 2) {
|
|
86
|
+
return html`<obi-hydraulic-07></obi-hydraulic-07>`;
|
|
87
|
+
}
|
|
88
|
+
switch (this.type) {
|
|
89
|
+
case HydraulicValve43Type.Two:
|
|
90
|
+
return html`<obi-hydraulic-16></obi-hydraulic-16>`;
|
|
91
|
+
case HydraulicValve43Type.Three:
|
|
92
|
+
return html`<obi-hydraulic-08></obi-hydraulic-08>`;
|
|
93
|
+
case HydraulicValve43Type.Four:
|
|
94
|
+
return html`<obi-hydraulic-05></obi-hydraulic-05>`;
|
|
95
|
+
case HydraulicValve43Type.Five:
|
|
96
|
+
return html`<obi-hydraulic-06></obi-hydraulic-06>`;
|
|
97
|
+
case HydraulicValve43Type.One:
|
|
98
|
+
default:
|
|
99
|
+
return html`<obi-hydraulic-01></obi-hydraulic-01>`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
declare global {
|
|
105
|
+
interface HTMLElementTagNameMap {
|
|
106
|
+
'obc-hydraulic-valve-4-3': ObcHydraulicValve43;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
|
+
import {html} from 'lit';
|
|
3
|
+
import {
|
|
4
|
+
HydraulicValveX2Type,
|
|
5
|
+
ObcHydraulicValveX2,
|
|
6
|
+
} from './hydraulic-valve-x-2.js';
|
|
7
|
+
import './hydraulic-valve-x-2.js';
|
|
8
|
+
import type {PositionSelectedEvent} from '../shuffle-button/shuffle-button-base.js';
|
|
9
|
+
|
|
10
|
+
const meta: Meta<typeof ObcHydraulicValveX2> = {
|
|
11
|
+
title: 'Automation/Hydraulic Valves/Valve X-2',
|
|
12
|
+
tags: ['autodocs', '6.1', 'experimental'],
|
|
13
|
+
component: 'obc-hydraulic-valve-x-2',
|
|
14
|
+
args: {
|
|
15
|
+
type: HydraulicValveX2Type.TwoTwo,
|
|
16
|
+
selectedPosition: 1,
|
|
17
|
+
vertical: false,
|
|
18
|
+
},
|
|
19
|
+
argTypes: {
|
|
20
|
+
type: {
|
|
21
|
+
control: {type: 'select'},
|
|
22
|
+
options: Object.values(HydraulicValveX2Type),
|
|
23
|
+
},
|
|
24
|
+
selectedPosition: {
|
|
25
|
+
control: {type: 'number', min: 0, max: 1, step: 1},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
render: (args) => html`
|
|
29
|
+
<obc-hydraulic-valve-x-2
|
|
30
|
+
type=${args.type}
|
|
31
|
+
.selectedPosition=${args.selectedPosition}
|
|
32
|
+
?vertical=${args.vertical}
|
|
33
|
+
@position-selected=${(event: PositionSelectedEvent) => {
|
|
34
|
+
(event.target as ObcHydraulicValveX2).selectedPosition =
|
|
35
|
+
event.detail.position;
|
|
36
|
+
}}
|
|
37
|
+
></obc-hydraulic-valve-x-2>
|
|
38
|
+
`,
|
|
39
|
+
} satisfies Meta<ObcHydraulicValveX2>;
|
|
40
|
+
|
|
41
|
+
export default meta;
|
|
42
|
+
type Story = StoryObj<ObcHydraulicValveX2>;
|
|
43
|
+
|
|
44
|
+
export const Default: Story = {};
|
|
45
|
+
|
|
46
|
+
export const TypeThreeTwo: Story = {
|
|
47
|
+
args: {type: HydraulicValveX2Type.ThreeTwo},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const TypeFourTwo: Story = {
|
|
51
|
+
args: {type: HydraulicValveX2Type.FourTwo},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const PositionFirst: Story = {
|
|
55
|
+
args: {selectedPosition: 0},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Vertical: Story = {
|
|
59
|
+
args: {vertical: true},
|
|
60
|
+
};
|