@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.154 → 2.0.0-next.156
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/LICENSE-AGPL.txt +661 -0
- package/LICENSE-APACHE.txt +177 -0
- package/LICENSE.txt +35 -0
- package/bundle/openbridge-webcomponents.bundle.js +3629 -3281
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +236 -37
- package/dist/automation/transmitter/transmitter-shared.d.ts +11 -0
- package/dist/automation/transmitter/transmitter-shared.d.ts.map +1 -0
- package/dist/automation/transmitter/transmitter-shared.js +16 -0
- package/dist/automation/transmitter/transmitter-shared.js.map +1 -0
- package/dist/automation/transmitter/transmitter.css.js +12 -1
- package/dist/automation/transmitter/transmitter.css.js.map +1 -1
- package/dist/automation/transmitter/transmitter.d.ts +9 -10
- package/dist/automation/transmitter/transmitter.d.ts.map +1 -1
- package/dist/automation/transmitter/transmitter.js +12 -15
- package/dist/automation/transmitter/transmitter.js.map +1 -1
- package/dist/automation/transmitter-button/transmitter-button.css.js +18 -42
- package/dist/automation/transmitter-button/transmitter-button.css.js.map +1 -1
- package/dist/automation/transmitter-button/transmitter-button.d.ts +31 -21
- package/dist/automation/transmitter-button/transmitter-button.d.ts.map +1 -1
- package/dist/automation/transmitter-button/transmitter-button.js +37 -39
- package/dist/automation/transmitter-button/transmitter-button.js.map +1 -1
- package/dist/automation/transmitter-stack/transmitter-stack.css.js +144 -0
- package/dist/automation/transmitter-stack/transmitter-stack.css.js.map +1 -0
- package/dist/automation/transmitter-stack/transmitter-stack.d.ts +93 -0
- package/dist/automation/transmitter-stack/transmitter-stack.d.ts.map +1 -0
- package/dist/automation/transmitter-stack/transmitter-stack.js +97 -0
- package/dist/automation/transmitter-stack/transmitter-stack.js.map +1 -0
- package/dist/building-blocks/readout-block/readout-block.d.ts +1 -1
- package/dist/building-blocks/readout-block/readout-block.js.map +1 -1
- package/dist/components/textarea-field/textarea-field.css.js +0 -2
- package/dist/components/textarea-field/textarea-field.css.js.map +1 -1
- package/dist/components/textbox/textbox.d.ts +1 -1
- package/dist/components/textbox/textbox.js.map +1 -1
- package/dist/components/user-button/user-button.css.js +68 -1
- package/dist/components/user-button/user-button.css.js.map +1 -1
- package/dist/components/user-button/user-button.d.ts +8 -1
- package/dist/components/user-button/user-button.d.ts.map +1 -1
- package/dist/components/user-button/user-button.js +12 -3
- package/dist/components/user-button/user-button.js.map +1 -1
- package/dist/components/user-menu/user-menu.css.js +15 -0
- package/dist/components/user-menu/user-menu.css.js.map +1 -1
- package/dist/components/user-menu/user-menu.d.ts +22 -2
- package/dist/components/user-menu/user-menu.d.ts.map +1 -1
- package/dist/components/user-menu/user-menu.js +34 -2
- package/dist/components/user-menu/user-menu.js.map +1 -1
- package/dist/generated/locales/es-419.d.ts +1 -0
- package/dist/generated/locales/es-419.d.ts.map +1 -1
- package/dist/generated/locales/es-419.js +1 -0
- package/dist/generated/locales/es-419.js.map +1 -1
- package/dist/generated/locales/fi-FI.d.ts +1 -0
- package/dist/generated/locales/fi-FI.d.ts.map +1 -1
- package/dist/generated/locales/fi-FI.js +1 -0
- package/dist/generated/locales/fi-FI.js.map +1 -1
- package/dist/navigation-instruments/readout/readout.d.ts +1 -1
- package/dist/navigation-instruments/readout/readout.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +1 -0
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js +3 -0
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
- package/package.json +6 -3
- package/script/prepare-full-bundle.ts +5 -0
- package/src/automation/transmitter/transmitter-shared.ts +16 -0
- package/src/automation/transmitter/transmitter.css +3 -71
- package/src/automation/transmitter/transmitter.stories.ts +13 -1
- package/src/automation/transmitter/transmitter.ts +19 -16
- package/src/automation/transmitter-button/transmitter-button.css +11 -36
- package/src/automation/transmitter-button/transmitter-button.stories.ts +3 -1
- package/src/automation/transmitter-button/transmitter-button.ts +62 -66
- package/src/automation/transmitter-stack/transmitter-stack.css +56 -0
- package/src/automation/transmitter-stack/transmitter-stack.spec.ts +210 -0
- package/src/automation/transmitter-stack/transmitter-stack.stories.ts +149 -0
- package/src/automation/transmitter-stack/transmitter-stack.ts +172 -0
- package/src/building-blocks/readout-block/readout-block.stories.ts +1 -1
- package/src/building-blocks/readout-block/readout-block.ts +1 -1
- package/src/components/textarea-field/textarea-field.css +1 -8
- package/src/components/textbox/textbox.stories.ts +1 -1
- package/src/components/textbox/textbox.ts +1 -1
- package/src/components/user-button/user-button.css +27 -1
- package/src/components/user-button/user-button.stories.ts +29 -0
- package/src/components/user-button/user-button.ts +22 -3
- package/src/components/user-menu/user-menu.css +8 -0
- package/src/components/user-menu/user-menu.stories.ts +53 -0
- package/src/components/user-menu/user-menu.ts +55 -4
- package/src/generated/locales/es-419.ts +1 -0
- package/src/generated/locales/fi-FI.ts +1 -0
- package/src/mixins/transmitter.css +90 -0
- package/src/mixins/visually-hidden.css +10 -0
- package/src/navigation-instruments/readout/readout.stories.ts +1 -1
- package/src/navigation-instruments/readout/readout.ts +1 -1
- package/src/navigation-instruments/readout-list-item/readout-list-item.css +1 -0
- package/src/navigation-instruments/readout-list-item/readout-list-item.stories.ts +1 -1
- package/src/navigation-instruments/readout-list-item/readout-list-item.ts +12 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
|
+
import {html} from 'lit';
|
|
3
|
+
import {
|
|
4
|
+
ObcTransmitterStack,
|
|
5
|
+
type TransmitterStackValue,
|
|
6
|
+
} from './transmitter-stack.js';
|
|
7
|
+
import './transmitter-stack.js';
|
|
8
|
+
import {TransmitterOrientation} from '../transmitter/transmitter.js';
|
|
9
|
+
import {crossDecorator} from '../../storybook-util.js';
|
|
10
|
+
import '../../icons/icon-temperature-air.js';
|
|
11
|
+
import '../../icons/icon-pressure.js';
|
|
12
|
+
import '../../icons/icon-placeholder.js';
|
|
13
|
+
import '../horizontal-line/horizontal-line.js';
|
|
14
|
+
import {LineMedium, LineType} from '../index.js';
|
|
15
|
+
|
|
16
|
+
const designValues: TransmitterStackValue[] = [
|
|
17
|
+
{
|
|
18
|
+
value: 12.3,
|
|
19
|
+
unit: 'C',
|
|
20
|
+
hasDegree: true,
|
|
21
|
+
idTag: '#0000',
|
|
22
|
+
iconSlotName: 'temperature',
|
|
23
|
+
},
|
|
24
|
+
{value: 12.3, unit: 'mVs', idTag: '#0000', iconSlotName: 'pressure'},
|
|
25
|
+
{value: 12.3, unit: 'm', idTag: '#0000', iconSlotName: 'level'},
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const meta: Meta<typeof ObcTransmitterStack> = {
|
|
29
|
+
title: 'Automation/Transmitter/Transmitter Stack',
|
|
30
|
+
tags: ['autodocs', 'experimental'],
|
|
31
|
+
component: 'obc-transmitter-stack',
|
|
32
|
+
decorators: [crossDecorator],
|
|
33
|
+
args: {
|
|
34
|
+
orientation: TransmitterOrientation.bottom,
|
|
35
|
+
lineType: LineType.fluid,
|
|
36
|
+
values: designValues,
|
|
37
|
+
},
|
|
38
|
+
argTypes: {
|
|
39
|
+
orientation: {
|
|
40
|
+
options: [
|
|
41
|
+
TransmitterOrientation.top,
|
|
42
|
+
TransmitterOrientation.right,
|
|
43
|
+
TransmitterOrientation.bottom,
|
|
44
|
+
TransmitterOrientation.left,
|
|
45
|
+
],
|
|
46
|
+
control: {type: 'radio'},
|
|
47
|
+
},
|
|
48
|
+
lineType: {
|
|
49
|
+
options: [
|
|
50
|
+
LineType.air,
|
|
51
|
+
LineType.connector,
|
|
52
|
+
LineType.electric,
|
|
53
|
+
LineType.fluid,
|
|
54
|
+
],
|
|
55
|
+
control: {type: 'radio'},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
} satisfies Meta<ObcTransmitterStack>;
|
|
59
|
+
|
|
60
|
+
export default meta;
|
|
61
|
+
type Story = StoryObj<ObcTransmitterStack>;
|
|
62
|
+
|
|
63
|
+
function renderComponent(args: ObcTransmitterStack) {
|
|
64
|
+
return html`
|
|
65
|
+
<obc-transmitter-stack
|
|
66
|
+
.orientation=${args.orientation}
|
|
67
|
+
.lineType=${args.lineType}
|
|
68
|
+
.values=${args.values}
|
|
69
|
+
>
|
|
70
|
+
<obi-temperature-air slot="temperature"></obi-temperature-air>
|
|
71
|
+
<obi-pressure slot="pressure"></obi-pressure>
|
|
72
|
+
<obi-placeholder slot="level"></obi-placeholder>
|
|
73
|
+
</obc-transmitter-stack>
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const Bottom: Story = {
|
|
78
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const Top: Story = {
|
|
82
|
+
args: {orientation: TransmitterOrientation.top},
|
|
83
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const Left: Story = {
|
|
87
|
+
args: {orientation: TransmitterOrientation.left},
|
|
88
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const Right: Story = {
|
|
92
|
+
args: {orientation: TransmitterOrientation.right},
|
|
93
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const WithoutIdTags: Story = {
|
|
97
|
+
args: {
|
|
98
|
+
values: designValues.map((entry) => ({...entry, idTag: undefined})),
|
|
99
|
+
},
|
|
100
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const MixedIdTags: Story = {
|
|
104
|
+
args: {
|
|
105
|
+
values: designValues.map((entry, index) => ({
|
|
106
|
+
...entry,
|
|
107
|
+
idTag: index === 0 ? '#0000' : undefined,
|
|
108
|
+
})),
|
|
109
|
+
},
|
|
110
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const MissingValues: Story = {
|
|
114
|
+
args: {
|
|
115
|
+
values: [
|
|
116
|
+
{...designValues[0], value: null, maxDigits: 3, hintedZeros: true},
|
|
117
|
+
{...designValues[1], value: NaN},
|
|
118
|
+
designValues[2],
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const UsageWithPipe: Story = {
|
|
125
|
+
render: (args) => html`
|
|
126
|
+
<style>
|
|
127
|
+
.canvas {
|
|
128
|
+
position: relative;
|
|
129
|
+
width: 400px;
|
|
130
|
+
height: 400px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#line-bottom {
|
|
134
|
+
position: absolute;
|
|
135
|
+
top: 0;
|
|
136
|
+
left: calc(-2.5 * 24px);
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
139
|
+
<div class="canvas">
|
|
140
|
+
${renderComponent(args as ObcTransmitterStack)}
|
|
141
|
+
<obc-horizontal-line
|
|
142
|
+
.medium=${LineMedium.water}
|
|
143
|
+
.lineType=${args.lineType || LineType.fluid}
|
|
144
|
+
length="5"
|
|
145
|
+
id="line-bottom"
|
|
146
|
+
></obc-horizontal-line>
|
|
147
|
+
</div>
|
|
148
|
+
`,
|
|
149
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import {LitElement, html, nothing, unsafeCSS} from 'lit';
|
|
2
|
+
import {property} from 'lit/decorators.js';
|
|
3
|
+
import {classMap} from 'lit/directives/class-map.js';
|
|
4
|
+
import componentStyle from './transmitter-stack.css?inline';
|
|
5
|
+
import {customElement} from '../../decorator.js';
|
|
6
|
+
import {LineType} from '../index.js';
|
|
7
|
+
import {
|
|
8
|
+
TransmitterOrientation,
|
|
9
|
+
transmitterLeaderOffset,
|
|
10
|
+
} from '../transmitter/transmitter-shared.js';
|
|
11
|
+
import {TransmitterButtonVariant} from '../transmitter-button/transmitter-button.js';
|
|
12
|
+
import '../transmitter-button/transmitter-button.js';
|
|
13
|
+
|
|
14
|
+
/** One reading of a transmitter stack. */
|
|
15
|
+
export interface TransmitterStackValue {
|
|
16
|
+
/** The reading; `null` or `NaN` renders the unavailable dash. */
|
|
17
|
+
value: number | null;
|
|
18
|
+
unit?: string;
|
|
19
|
+
/** Identifier shown under the segment (above it for `top`) and read as part of its name. */
|
|
20
|
+
idTag?: string;
|
|
21
|
+
/** Decimal precision; `1` when the key is omitted. */
|
|
22
|
+
fractionDigits?: number;
|
|
23
|
+
/** Integer digits to reserve; `0` when the key is omitted. */
|
|
24
|
+
maxDigits?: number;
|
|
25
|
+
hintedZeros?: boolean;
|
|
26
|
+
hasSignSpacer?: boolean;
|
|
27
|
+
/** Show a degree column between the value and the unit (e.g. `12.3°` then `C`). */
|
|
28
|
+
hasDegree?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Name of the light-DOM slot projected as this segment's icon. Unique within
|
|
31
|
+
* the stack: an element is projected once, so a repeated name leaves later
|
|
32
|
+
* segments with an empty icon.
|
|
33
|
+
*/
|
|
34
|
+
iconSlotName?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TransmitterStackValueClickDetail {
|
|
38
|
+
index: number;
|
|
39
|
+
value: TransmitterStackValue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `<obc-transmitter-stack>` – Several transmitter readings side by side in one
|
|
44
|
+
* joined chip, attached to a line by a single leader line.
|
|
45
|
+
*
|
|
46
|
+
* Each entry of `values` renders an `<obc-transmitter-button>` segment with its
|
|
47
|
+
* own icon, value, unit and id tag. The segments take equal widths, set by the
|
|
48
|
+
* widest reading, and share their borders. Positioning and the leader line
|
|
49
|
+
* follow `<obc-transmitter>`.
|
|
50
|
+
*
|
|
51
|
+
* ### Features / Variants
|
|
52
|
+
* - **`orientation`** – `top`, `right`, `bottom`, `left`; the edge the leader
|
|
53
|
+
* line attaches to. `top` places the id tags above the chip.
|
|
54
|
+
* - **Values** – `value` and `unit` per segment. `idTag` adds a label row under
|
|
55
|
+
* every segment once any value has one, so the chip stays aligned.
|
|
56
|
+
* - **Formatting** – per value `fractionDigits` (default `1`), `maxDigits`
|
|
57
|
+
* (default `0`), `hintedZeros`, `hasSignSpacer` and `hasDegree`, formatted like
|
|
58
|
+
* `<obc-transmitter-button>`. An omitted key takes its default; a key set to
|
|
59
|
+
* `null`, `undefined` or `NaN` renders the reading as the unavailable dash.
|
|
60
|
+
* - **Icons** – `iconSlotName` projects the light-DOM element with that slot
|
|
61
|
+
* name as the segment's icon; names must be unique within the stack. The
|
|
62
|
+
* name is chosen per value, so it carries no `@slot` tag (the wrapper
|
|
63
|
+
* generator needs literal names).
|
|
64
|
+
* - **Accessible name** – each segment is a native button named by its
|
|
65
|
+
* reading, unit and `idTag`; the visible tag is hidden from assistive
|
|
66
|
+
* technology so it is not read twice.
|
|
67
|
+
* - **Empty** – with no `values` nothing renders, leader line included.
|
|
68
|
+
*
|
|
69
|
+
* ### Usage Guidelines
|
|
70
|
+
* Use when one source reports several readings that share one leader line. For
|
|
71
|
+
* a single reading, a tag pill or a trend graph, use `<obc-transmitter>`. Each
|
|
72
|
+
* segment's hit area is `<obc-transmitter-button>`'s chip (24 px high), below
|
|
73
|
+
* the 48 px touch-target token; see its design note.
|
|
74
|
+
*
|
|
75
|
+
* ### Slots
|
|
76
|
+
* | Slot Name | Conditions | Purpose |
|
|
77
|
+
* |------------------|---------------------------------|-------------------------------|
|
|
78
|
+
* | `<iconSlotName>` | a value declares `iconSlotName` | Icon in that value's segment. |
|
|
79
|
+
*
|
|
80
|
+
* @property orientation - Edge of the chip the leader line attaches to.
|
|
81
|
+
* @property lineType - Line the transmitter sits on; offsets the leader line by half its stroke.
|
|
82
|
+
* @property values - One segment per entry, in order.
|
|
83
|
+
* @fires {CustomEvent<TransmitterStackValueClickDetail>} value-click - Fired when a segment is activated, with its value and index.
|
|
84
|
+
* @fires click - Fired when any segment is clicked; `value-click` tells which.
|
|
85
|
+
* @experimental
|
|
86
|
+
*/
|
|
87
|
+
@customElement('obc-transmitter-stack')
|
|
88
|
+
export class ObcTransmitterStack extends LitElement {
|
|
89
|
+
@property({type: String}) orientation: TransmitterOrientation =
|
|
90
|
+
TransmitterOrientation.bottom;
|
|
91
|
+
@property({type: String}) lineType: LineType | undefined = undefined;
|
|
92
|
+
@property({type: Array}) values: TransmitterStackValue[] = [];
|
|
93
|
+
|
|
94
|
+
private handleValueClick(index: number, value: TransmitterStackValue): void {
|
|
95
|
+
this.dispatchEvent(
|
|
96
|
+
new CustomEvent<TransmitterStackValueClickDetail>('value-click', {
|
|
97
|
+
detail: {index, value},
|
|
98
|
+
bubbles: true,
|
|
99
|
+
composed: true,
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private renderValue(
|
|
105
|
+
entry: TransmitterStackValue,
|
|
106
|
+
index: number,
|
|
107
|
+
hasIdTags: boolean
|
|
108
|
+
) {
|
|
109
|
+
// `in`, not `??` alone: a key that is present but empty is a failed
|
|
110
|
+
// runtime write and must reach the block as missing (NaN renders the dash,
|
|
111
|
+
// readout-components.md § 2).
|
|
112
|
+
return html`
|
|
113
|
+
<div class="cell" part="cell">
|
|
114
|
+
<obc-transmitter-button
|
|
115
|
+
class="segment"
|
|
116
|
+
.variant=${TransmitterButtonVariant.value}
|
|
117
|
+
.value=${entry.value}
|
|
118
|
+
.unit=${entry.unit ?? ''}
|
|
119
|
+
.fractionDigits=${'fractionDigits' in entry
|
|
120
|
+
? (entry.fractionDigits ?? NaN)
|
|
121
|
+
: 1}
|
|
122
|
+
.maxDigits=${'maxDigits' in entry ? (entry.maxDigits ?? NaN) : 0}
|
|
123
|
+
.hintedZeros=${entry.hintedZeros ?? false}
|
|
124
|
+
.hasSignSpacer=${entry.hasSignSpacer ?? false}
|
|
125
|
+
.hasDegree=${entry.hasDegree ?? false}
|
|
126
|
+
.hasIcon=${Boolean(entry.iconSlotName)}
|
|
127
|
+
.idTag=${entry.idTag ?? ''}
|
|
128
|
+
@click=${() => this.handleValueClick(index, entry)}
|
|
129
|
+
>
|
|
130
|
+
${entry.iconSlotName
|
|
131
|
+
? html`<slot name=${entry.iconSlotName} slot="icon"></slot>`
|
|
132
|
+
: nothing}
|
|
133
|
+
</obc-transmitter-button>
|
|
134
|
+
${hasIdTags
|
|
135
|
+
? html`<div class="id-tag" aria-hidden="true">
|
|
136
|
+
${entry.idTag ?? ''}
|
|
137
|
+
</div>`
|
|
138
|
+
: nothing}
|
|
139
|
+
</div>
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
override render() {
|
|
144
|
+
if (this.values.length === 0) {
|
|
145
|
+
return nothing;
|
|
146
|
+
}
|
|
147
|
+
const hasIdTags = this.values.some((entry) => Boolean(entry.idTag));
|
|
148
|
+
return html`
|
|
149
|
+
<div
|
|
150
|
+
class=${classMap({
|
|
151
|
+
transmitter: true,
|
|
152
|
+
[`orientation-${this.orientation}`]: true,
|
|
153
|
+
})}
|
|
154
|
+
style="--offset: ${transmitterLeaderOffset(this.lineType)}px;"
|
|
155
|
+
>
|
|
156
|
+
<div class="values" part="values">
|
|
157
|
+
${this.values.map((entry, index) =>
|
|
158
|
+
this.renderValue(entry, index, hasIdTags)
|
|
159
|
+
)}
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static override styles = unsafeCSS(componentStyle);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
declare global {
|
|
169
|
+
interface HTMLElementTagNameMap {
|
|
170
|
+
'obc-transmitter-stack': ObcTransmitterStack;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -122,7 +122,7 @@ function renderShowcase(cards: ShowcaseCard[]) {
|
|
|
122
122
|
|
|
123
123
|
const meta = {
|
|
124
124
|
title: 'Building Blocks/Readout Block',
|
|
125
|
-
tags: ['autodocs', '6.0'
|
|
125
|
+
tags: ['autodocs', '6.0'],
|
|
126
126
|
component: 'obc-readout-block',
|
|
127
127
|
decorators: [themedDecorator],
|
|
128
128
|
parameters: {
|
|
@@ -201,7 +201,7 @@ export enum ReadoutBlockHidePhase {
|
|
|
201
201
|
* @csspart block-text - The `obc-textbox` rendering the number.
|
|
202
202
|
* @csspart block-icon - The leading marker-icon container.
|
|
203
203
|
* @csspart degree - The trailing degree-glyph column.
|
|
204
|
-
* @
|
|
204
|
+
* @stable
|
|
205
205
|
*/
|
|
206
206
|
@customElement('obc-readout-block')
|
|
207
207
|
export class ObcReadoutBlock extends LitElement {
|
|
@@ -325,13 +325,6 @@ obc-audio-recording-item {
|
|
|
325
325
|
--on-normal-neutral-color: var(--element-inactive-color);
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
-
/* Visually hidden but accessible to screen readers */
|
|
329
328
|
.visually-hidden {
|
|
330
|
-
|
|
331
|
-
clip-path: inset(50%);
|
|
332
|
-
height: 1px;
|
|
333
|
-
overflow: hidden;
|
|
334
|
-
position: absolute;
|
|
335
|
-
white-space: nowrap;
|
|
336
|
-
width: 1px;
|
|
329
|
+
@mixin visually-hidden;
|
|
337
330
|
}
|
|
@@ -15,7 +15,7 @@ interface TextboxStoryArgs extends Partial<ObcTextbox> {
|
|
|
15
15
|
|
|
16
16
|
const meta: Meta<TextboxStoryArgs> = {
|
|
17
17
|
title: 'Building Blocks/Textbox',
|
|
18
|
-
tags: ['autodocs', '6.0'
|
|
18
|
+
tags: ['autodocs', '6.0'],
|
|
19
19
|
component: 'obc-textbox',
|
|
20
20
|
args: {
|
|
21
21
|
size: ObcTextboxSize.m,
|
|
@@ -66,7 +66,7 @@ export enum ObcTextboxFontWeight {
|
|
|
66
66
|
*
|
|
67
67
|
* @slot - The visible text content.
|
|
68
68
|
* @slot length - Reserves a minimum width based on its content width.
|
|
69
|
-
* @
|
|
69
|
+
* @stable
|
|
70
70
|
*/
|
|
71
71
|
@customElement('obc-textbox')
|
|
72
72
|
export class ObcTextbox extends LitElement {
|
|
@@ -37,10 +37,26 @@
|
|
|
37
37
|
@mixin font-subtitle;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
.user-label {
|
|
41
|
+
@mixin font-body;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.user-sublabel {
|
|
45
|
+
@mixin font-body;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.has-sublabel .user-label {
|
|
49
|
+
@mixin font-body-active;
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
&.style-selected .user-initials {
|
|
41
53
|
@mixin font-title;
|
|
42
54
|
}
|
|
43
55
|
|
|
56
|
+
&.style-selected .user-label {
|
|
57
|
+
@mixin font-body-active;
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
&.state-static {
|
|
45
61
|
width: var(--ui-components-user-button-visual-size-enhanced);
|
|
46
62
|
height: var(--ui-components-user-button-visual-size-enhanced);
|
|
@@ -55,7 +71,17 @@
|
|
|
55
71
|
color: var(--element-active-color);
|
|
56
72
|
}
|
|
57
73
|
|
|
58
|
-
|
|
74
|
+
.user-sublabel {
|
|
75
|
+
@mixin font-label;
|
|
76
|
+
color: var(--element-active-color);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&.has-sublabel .user-label {
|
|
80
|
+
@mixin font-label-active;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&:disabled .user-label,
|
|
84
|
+
&:disabled .user-sublabel {
|
|
59
85
|
color: var(--element-disabled-color);
|
|
60
86
|
}
|
|
61
87
|
|
|
@@ -175,3 +175,32 @@ export const TooManyInitials: Story = {
|
|
|
175
175
|
styleType: StyleType.flat,
|
|
176
176
|
},
|
|
177
177
|
};
|
|
178
|
+
|
|
179
|
+
export const WithSublabel: Story = {
|
|
180
|
+
args: {
|
|
181
|
+
variant: Variant.initials,
|
|
182
|
+
styleType: StyleType.normal,
|
|
183
|
+
label: 'Anna',
|
|
184
|
+
sublabel: 'Captain',
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const LargeWithSublabel: Story = {
|
|
189
|
+
args: {
|
|
190
|
+
variant: Variant.initials,
|
|
191
|
+
styleType: StyleType.normal,
|
|
192
|
+
size: Size.large,
|
|
193
|
+
label: 'Anna',
|
|
194
|
+
sublabel: 'Captain',
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export const StaticWithSublabel: Story = {
|
|
199
|
+
args: {
|
|
200
|
+
variant: Variant.initials,
|
|
201
|
+
styleType: StyleType.normal,
|
|
202
|
+
static: true,
|
|
203
|
+
label: 'Anna',
|
|
204
|
+
sublabel: 'Captain',
|
|
205
|
+
},
|
|
206
|
+
};
|
|
@@ -50,6 +50,8 @@ export enum Variant {
|
|
|
50
50
|
* - Provide a custom icon via the `icon` slot when using the `icon` variant.
|
|
51
51
|
* - **Label Support:**
|
|
52
52
|
* - Optional `label` property displays text next to the button (not shown in static mode).
|
|
53
|
+
* - Optional `sublabel` adds a second, lighter line under the label, for a
|
|
54
|
+
* secondary detail such as the user's role.
|
|
53
55
|
*
|
|
54
56
|
* ## Usage Guidelines
|
|
55
57
|
* Use `obc-user-button` to represent a user in navigation bars, toolbars, or menus where a compact, recognizable user indicator is needed. Ideal for profile menus, account switching, or user-related quick actions.
|
|
@@ -71,7 +73,8 @@ export enum Variant {
|
|
|
71
73
|
* - Initials longer than two characters are truncated and a warning is logged.
|
|
72
74
|
* - If `initials` is empty or invalid, the button falls back to the user icon.
|
|
73
75
|
* - The `label` is only visible when the button is interactive (not static).
|
|
74
|
-
* - For accessibility, the button
|
|
76
|
+
* - For accessibility, the button is named after its visible text — `label` and
|
|
77
|
+
* `sublabel` — falling back to the initials when it shows no text.
|
|
75
78
|
* - Only use the `static` property for non-interactive contexts; otherwise, the button is clickable.
|
|
76
79
|
*
|
|
77
80
|
* ## Example:
|
|
@@ -88,6 +91,8 @@ export enum Variant {
|
|
|
88
91
|
* @availableWhen disabled static==false
|
|
89
92
|
* @property label - Optional label text to display next to the button (not shown in static mode).
|
|
90
93
|
* @availableWhen label static==false
|
|
94
|
+
* @property sublabel - Optional second line under the label, for a secondary detail such as a role (not shown in static mode).
|
|
95
|
+
* @availableWhen sublabel static==false
|
|
91
96
|
* @slot icon - Custom icon for the user button (used only in `icon` variant; defaults to <obi-user> if not provided)
|
|
92
97
|
* @stable
|
|
93
98
|
*/
|
|
@@ -122,6 +127,8 @@ export class ObcUserButton extends LitElement {
|
|
|
122
127
|
|
|
123
128
|
@property({type: String}) label?: string;
|
|
124
129
|
|
|
130
|
+
@property({type: String}) sublabel?: string;
|
|
131
|
+
|
|
125
132
|
private get formattedInitials() {
|
|
126
133
|
if (!this.initials) return '';
|
|
127
134
|
|
|
@@ -157,21 +164,33 @@ export class ObcUserButton extends LitElement {
|
|
|
157
164
|
'mode-initials': !this.shouldShowIcon,
|
|
158
165
|
'state-static': this.static,
|
|
159
166
|
[`size-${this.size}`]: true,
|
|
167
|
+
'has-sublabel': Boolean(this.sublabel) && !this.static,
|
|
160
168
|
};
|
|
161
169
|
|
|
162
170
|
// Use button element when clickable, div when static
|
|
163
171
|
const tag = this.static ? literal`div` : literal`button`;
|
|
164
172
|
|
|
173
|
+
const visibleText = [this.label, this.sublabel].filter(Boolean).join(', ');
|
|
174
|
+
const accessibleName =
|
|
175
|
+
(!this.static && visibleText) || this.initials || 'User button';
|
|
176
|
+
|
|
165
177
|
const label =
|
|
166
178
|
this.label && !this.static
|
|
167
179
|
? html`<span class="user-label" part="label">${this.label}</span>`
|
|
168
180
|
: nothing;
|
|
169
181
|
|
|
182
|
+
const sublabel =
|
|
183
|
+
this.sublabel && !this.static
|
|
184
|
+
? html`<span class="user-sublabel" part="sublabel">
|
|
185
|
+
${this.sublabel}
|
|
186
|
+
</span>`
|
|
187
|
+
: nothing;
|
|
188
|
+
|
|
170
189
|
return html`
|
|
171
190
|
<${tag}
|
|
172
191
|
class=${classMap(wrapperClasses)}
|
|
173
192
|
?disabled=${this.disabled}
|
|
174
|
-
aria-label=${
|
|
193
|
+
aria-label=${accessibleName}
|
|
175
194
|
>
|
|
176
195
|
<div class="content-container" part="content-container">
|
|
177
196
|
<div class="user-button-circle">
|
|
@@ -192,7 +211,7 @@ export class ObcUserButton extends LitElement {
|
|
|
192
211
|
`
|
|
193
212
|
}
|
|
194
213
|
</div>
|
|
195
|
-
${label}
|
|
214
|
+
${label} ${sublabel}
|
|
196
215
|
</div>
|
|
197
216
|
</${tag}>
|
|
198
217
|
`;
|
|
@@ -142,6 +142,14 @@
|
|
|
142
142
|
@mixin font-overline;
|
|
143
143
|
color: var(--element-neutral-color);
|
|
144
144
|
}
|
|
145
|
+
|
|
146
|
+
obc-user-button:not(.has-role)::part(label) {
|
|
147
|
+
font-weight: var(--font-weight-regular);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
obc-user-button::part(sublabel) {
|
|
151
|
+
@mixin font-body;
|
|
152
|
+
}
|
|
145
153
|
}
|
|
146
154
|
|
|
147
155
|
.user-primary {
|
|
@@ -16,6 +16,7 @@ const meta: Meta<ObcUserMenu> = {
|
|
|
16
16
|
'sign-out-click',
|
|
17
17
|
'signed-in-action-click',
|
|
18
18
|
'recent-user-click',
|
|
19
|
+
'use-another-account-click',
|
|
19
20
|
],
|
|
20
21
|
},
|
|
21
22
|
},
|
|
@@ -50,6 +51,8 @@ const meta: Meta<ObcUserMenu> = {
|
|
|
50
51
|
passwordError: '',
|
|
51
52
|
userInitials: 'AB',
|
|
52
53
|
userLabel: 'Username',
|
|
54
|
+
userRole: '',
|
|
55
|
+
showUseAnotherAccount: true,
|
|
53
56
|
recentUsers: [
|
|
54
57
|
{initials: 'AB', label: 'Username'},
|
|
55
58
|
{initials: 'CD', label: 'Username'},
|
|
@@ -77,6 +80,8 @@ const meta: Meta<ObcUserMenu> = {
|
|
|
77
80
|
passwordError=${args.passwordError}
|
|
78
81
|
.userInitials=${args.userInitials}
|
|
79
82
|
.userLabel=${args.userLabel}
|
|
83
|
+
.userRole=${args.userRole}
|
|
84
|
+
.showUseAnotherAccount=${args.showUseAnotherAccount}
|
|
80
85
|
.recentUsers=${args.recentUsers}
|
|
81
86
|
.signedInActions=${args.signedInActions}
|
|
82
87
|
.primaryActionId=${args.primaryActionId}
|
|
@@ -185,6 +190,54 @@ export const SignedInWithoutActions: Story = {
|
|
|
185
190
|
},
|
|
186
191
|
};
|
|
187
192
|
|
|
193
|
+
export const UserSignInWithRoles: Story = {
|
|
194
|
+
args: {
|
|
195
|
+
type: ObcUserMenuType.userSignIn,
|
|
196
|
+
size: ObcUserMenuSize.regular,
|
|
197
|
+
hasRecentlySignedIn: true,
|
|
198
|
+
userRole: 'Role',
|
|
199
|
+
recentUsers: [
|
|
200
|
+
{initials: 'AB', label: 'Username', role: 'Role'},
|
|
201
|
+
{initials: 'CD', label: 'Username', role: 'Role'},
|
|
202
|
+
{initials: 'EF', label: 'Username', role: 'Role'},
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const SignedInWithRole: Story = {
|
|
208
|
+
args: {
|
|
209
|
+
type: ObcUserMenuType.signedIn,
|
|
210
|
+
size: ObcUserMenuSize.regular,
|
|
211
|
+
userRole: 'Role',
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export const UserSignInWithoutUseAnotherAccount: Story = {
|
|
216
|
+
args: {
|
|
217
|
+
type: ObcUserMenuType.userSignIn,
|
|
218
|
+
size: ObcUserMenuSize.regular,
|
|
219
|
+
showUseAnotherAccount: false,
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export const UserSignInSmallWithoutUseAnotherAccount: Story = {
|
|
224
|
+
args: {
|
|
225
|
+
type: ObcUserMenuType.userSignIn,
|
|
226
|
+
size: ObcUserMenuSize.small,
|
|
227
|
+
showUseAnotherAccount: false,
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
export const UserSignInSmallIgnoresRole: Story = {
|
|
232
|
+
args: {
|
|
233
|
+
type: ObcUserMenuType.userSignIn,
|
|
234
|
+
size: ObcUserMenuSize.small,
|
|
235
|
+
hasRecentlySignedIn: true,
|
|
236
|
+
userRole: 'Role',
|
|
237
|
+
recentUsers: [{initials: 'AB', label: 'Username', role: 'Role'}],
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
|
|
188
241
|
export const SignInWithoutRecentUsers: Story = {
|
|
189
242
|
args: {
|
|
190
243
|
type: ObcUserMenuType.signIn,
|