@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.144 → 2.0.0-next.145

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 (30) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +4736 -4470
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +206 -21
  4. package/dist/components/checkbox-item/checkbox-item.css.js +137 -12
  5. package/dist/components/checkbox-item/checkbox-item.css.js.map +1 -1
  6. package/dist/components/checkbox-item/checkbox-item.d.ts +68 -39
  7. package/dist/components/checkbox-item/checkbox-item.d.ts.map +1 -1
  8. package/dist/components/checkbox-item/checkbox-item.js +66 -25
  9. package/dist/components/checkbox-item/checkbox-item.js.map +1 -1
  10. package/dist/components/checkbox-list/checkbox-list-visibility.d.ts +16 -0
  11. package/dist/components/checkbox-list/checkbox-list-visibility.d.ts.map +1 -0
  12. package/dist/components/checkbox-list/checkbox-list-visibility.js +12 -0
  13. package/dist/components/checkbox-list/checkbox-list-visibility.js.map +1 -0
  14. package/dist/components/checkbox-list/checkbox-list.css.js +23 -0
  15. package/dist/components/checkbox-list/checkbox-list.css.js.map +1 -0
  16. package/dist/components/checkbox-list/checkbox-list.d.ts +66 -0
  17. package/dist/components/checkbox-list/checkbox-list.d.ts.map +1 -0
  18. package/dist/components/checkbox-list/checkbox-list.js +81 -0
  19. package/dist/components/checkbox-list/checkbox-list.js.map +1 -0
  20. package/package.json +1 -1
  21. package/src/components/checkbox-item/checkbox-item.css +63 -17
  22. package/src/components/checkbox-item/checkbox-item.spec.ts +115 -0
  23. package/src/components/checkbox-item/checkbox-item.stories.ts +82 -97
  24. package/src/components/checkbox-item/checkbox-item.ts +118 -64
  25. package/src/components/checkbox-list/checkbox-list-visibility.spec.ts +68 -0
  26. package/src/components/checkbox-list/checkbox-list-visibility.ts +23 -0
  27. package/src/components/checkbox-list/checkbox-list.css +13 -0
  28. package/src/components/checkbox-list/checkbox-list.spec.ts +93 -0
  29. package/src/components/checkbox-list/checkbox-list.stories.ts +161 -0
  30. package/src/components/checkbox-list/checkbox-list.ts +130 -0
@@ -16,36 +16,79 @@
16
16
  user-select: none;
17
17
  cursor: pointer;
18
18
 
19
+ &.has-description {
20
+ /* a second text line outgrows the fixed row; the hover surface follows */
21
+ height: auto;
22
+ min-height: var(--ui-components-checkbox-touch-target-size);
23
+ }
24
+
19
25
  &.disabled {
20
26
  cursor: not-allowed;
21
27
  }
22
28
 
23
- .chevron-container,
24
- .nested-spacer {
29
+ .chevron-container {
25
30
  display: flex;
26
31
  width: var(--global-size-spacing-touch-target-min);
27
- height: var(--global-size-spacing-touch-target-min);
28
32
  min-width: var(--global-size-spacing-touch-target-min);
29
- min-height: var(--global-size-spacing-touch-target-min);
30
- padding: 0px;
33
+ height: var(--global-size-spacing-touch-target-min);
31
34
  align-items: center;
32
35
  justify-content: center;
33
36
  flex-shrink: 0;
34
37
  }
35
38
 
39
+ .nested-spacer {
40
+ /* one indent step per level above 1; --checkbox-item-depth is set inline */
41
+ width: calc(
42
+ var(--checkbox-item-depth, 0) *
43
+ var(--ui-components-checkbox-nested-item-padding-left)
44
+ );
45
+ flex-shrink: 0;
46
+ align-self: stretch;
47
+ }
48
+
49
+ .chevron-button {
50
+ @mixin style style=flat visibleWrapperClass=.chevron-visible;
51
+ appearance: none;
52
+ border: none;
53
+ background: transparent;
54
+ padding: 0;
55
+ width: 100%;
56
+ height: 100%;
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ cursor: pointer;
61
+ color: var(--on-flat-neutral-color);
62
+
63
+ &:disabled {
64
+ cursor: not-allowed;
65
+ }
66
+ }
67
+
68
+ .chevron-visible {
69
+ /* same visible box as obc-icon-button so the two align in one list */
70
+ width: var(--ui-components-icon-button-visual-target-size);
71
+ height: var(--ui-components-icon-button-visual-target-size);
72
+ border-radius: var(--ui-components-button-border-radius-top-left);
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ }
77
+
36
78
  .chevron-icon {
37
79
  width: var(--global-size-spacing-icon-icon-size-regular);
38
80
  height: var(--global-size-spacing-icon-icon-size-regular);
39
- color: var(--on-flat-neutral-color);
40
81
  }
41
82
 
42
83
  .checkbox-label-container {
43
84
  display: flex;
85
+ flex-direction: column;
86
+ justify-content: center;
87
+ min-width: 0; /* lets the label ellipsis instead of widening the row */
44
88
  padding: 0 var(--global-size-spacing-list-item-padding-vertical) 0 0;
45
89
  margin-left: calc(
46
90
  var(--global-size-spacing-list-item-padding-vertical) / -2
47
91
  );
48
- align-items: center;
49
92
  flex-grow: 1;
50
93
  }
51
94
 
@@ -65,6 +108,18 @@
65
108
  color: var(--element-disabled-color);
66
109
  }
67
110
  }
111
+
112
+ .checkbox-description {
113
+ color: var(--element-active-color);
114
+ @mixin font-label;
115
+ white-space: nowrap;
116
+ overflow: hidden;
117
+ text-overflow: ellipsis;
118
+
119
+ .disabled & {
120
+ color: var(--element-disabled-color);
121
+ }
122
+ }
68
123
  }
69
124
 
70
125
  .checkbox-item-container.hover-style-touch-target {
@@ -73,12 +128,6 @@
73
128
 
74
129
  .checkbox-item-container.hover-style-visual-target {
75
130
  @mixin style style=flat noClick visibleWrapperClass=.content-container;
76
-
77
- .chevron-container,
78
- .nested-spacer {
79
- width: var(--ui-components-checkbox-nested-item-padding-left);
80
- min-width: var(--ui-components-checkbox-nested-item-padding-left);
81
- }
82
131
  }
83
132
 
84
133
  .content-container {
@@ -92,10 +141,7 @@
92
141
  box-shadow: none;
93
142
  border-radius: var(--ui-components-checkbox-list-item-border-radius);
94
143
 
95
- .checkbox-item-container.hover-style-visual-target:not(.is-nested):not(
96
- .is-level-1
97
- ):not(.is-level-2)
98
- & {
144
+ .checkbox-item-container.hover-style-visual-target:not(.is-nested) & {
99
145
  margin-left: calc(var(--ui-components-checkbox-padding-horizontal) * -1);
100
146
  }
101
147
 
@@ -0,0 +1,115 @@
1
+ import {afterEach, describe, expect, it} from 'vitest';
2
+ import './checkbox-item.js';
3
+ import type {ObcCheckboxItem} from './checkbox-item.js';
4
+
5
+ async function mount(setup: (el: ObcCheckboxItem) => void = () => {}) {
6
+ const el = document.createElement('obc-checkbox-item');
7
+ el.label = 'Label';
8
+ setup(el);
9
+ document.body.appendChild(el);
10
+ await el.updateComplete;
11
+ return el;
12
+ }
13
+
14
+ const sr = (el: ObcCheckboxItem) => el.shadowRoot!;
15
+
16
+ afterEach(() => {
17
+ document.body.innerHTML = '';
18
+ });
19
+
20
+ describe('obc-checkbox-item level', () => {
21
+ it('level 0 renders neither chevron slot nor spacer', async () => {
22
+ const el = await mount();
23
+ expect(sr(el).querySelector('.chevron-container')).toBeNull();
24
+ expect(sr(el).querySelector('.nested-spacer')).toBeNull();
25
+ });
26
+
27
+ it('level 1 reserves the chevron slot without a button', async () => {
28
+ const el = await mount((e) => (e.level = 1));
29
+ expect(sr(el).querySelector('.chevron-container')).not.toBeNull();
30
+ expect(sr(el).querySelector('.chevron-button')).toBeNull();
31
+ expect(sr(el).querySelector('.nested-spacer')).toBeNull();
32
+ });
33
+
34
+ it('level 3 exposes depth 2 to CSS through the spacer', async () => {
35
+ const el = await mount((e) => (e.level = 3));
36
+ const spacer = sr(el).querySelector<HTMLElement>('.nested-spacer')!;
37
+ expect(spacer.style.getPropertyValue('--checkbox-item-depth')).toBe('2');
38
+ });
39
+
40
+ it('reflects level, expandable and expanded as attributes', async () => {
41
+ const el = await mount((e) => {
42
+ e.level = 2;
43
+ e.expandable = true;
44
+ e.expanded = true;
45
+ });
46
+ expect(el.getAttribute('level')).toBe('2');
47
+ expect(el.hasAttribute('expandable')).toBe(true);
48
+ expect(el.hasAttribute('expanded')).toBe(true);
49
+ });
50
+ });
51
+
52
+ describe('obc-checkbox-item expandable', () => {
53
+ it('renders a chevron button with aria-expanded', async () => {
54
+ const el = await mount((e) => {
55
+ e.level = 1;
56
+ e.expandable = true;
57
+ });
58
+ const btn = sr(el).querySelector<HTMLButtonElement>('.chevron-button')!;
59
+ expect(btn).not.toBeNull();
60
+ expect(btn.getAttribute('aria-expanded')).toBe('false');
61
+ expect(btn.getAttribute('aria-label')).toBe('Label');
62
+ expect(sr(el).querySelector('obi-chevron-right-google')).not.toBeNull();
63
+ el.expanded = true;
64
+ await el.updateComplete;
65
+ expect(btn.getAttribute('aria-expanded')).toBe('true');
66
+ expect(sr(el).querySelector('obi-chevron-down-google')).not.toBeNull();
67
+ });
68
+
69
+ it('expandable at level 0 still renders the chevron slot', async () => {
70
+ const el = await mount((e) => (e.expandable = true));
71
+ expect(sr(el).querySelector('.chevron-button')).not.toBeNull();
72
+ });
73
+
74
+ it('chevron click fires expand-toggle with the next value and no change', async () => {
75
+ const el = await mount((e) => {
76
+ e.level = 1;
77
+ e.expandable = true;
78
+ });
79
+ const toggles: boolean[] = [];
80
+ let changes = 0;
81
+ el.addEventListener('expand-toggle', (e) =>
82
+ toggles.push((e as CustomEvent<boolean>).detail)
83
+ );
84
+ el.addEventListener('change', () => changes++);
85
+ sr(el).querySelector<HTMLButtonElement>('.chevron-button')!.click();
86
+ expect(toggles).toEqual([true]);
87
+ expect(changes).toBe(0);
88
+ expect(el.expanded).toBe(false);
89
+ expect(el.status).toBe('unchecked');
90
+ });
91
+
92
+ it('row click still toggles the checkbox', async () => {
93
+ const el = await mount((e) => {
94
+ e.level = 1;
95
+ e.expandable = true;
96
+ });
97
+ let changes = 0;
98
+ el.addEventListener('change', () => changes++);
99
+ sr(el).querySelector<HTMLElement>('.checkbox-label')!.click();
100
+ expect(changes).toBe(1);
101
+ expect(el.status).toBe('checked');
102
+ });
103
+ });
104
+
105
+ describe('obc-checkbox-item description', () => {
106
+ it('renders the description only when non-empty', async () => {
107
+ const el = await mount();
108
+ expect(sr(el).querySelector('.checkbox-description')).toBeNull();
109
+ el.description = 'More detail';
110
+ await el.updateComplete;
111
+ expect(sr(el).querySelector('.checkbox-description')!.textContent).toBe(
112
+ 'More detail'
113
+ );
114
+ });
115
+ });
@@ -14,15 +14,18 @@ const statusVariants = [
14
14
  CheckboxStatus.mixed,
15
15
  ] as const;
16
16
 
17
- const renderStatusGroup = (opts: {
18
- state: ObcCheckboxItemState;
17
+ type RowOptions = {
19
18
  hoverStyle: ObcCheckboxItemHoverStyle;
20
- disabled: boolean;
21
19
  label: string;
22
- isNested: boolean;
23
- isLevel1: boolean;
24
- isLevel2: boolean;
25
- }) => html`
20
+ description: string;
21
+ level: number;
22
+ expandable: boolean;
23
+ expanded: boolean;
24
+ };
25
+
26
+ const renderStatusGroup = (
27
+ opts: RowOptions & {state: ObcCheckboxItemState; disabled: boolean}
28
+ ) => html`
26
29
  <div style="display:flex; justify-content:flex-start; width:100%;">
27
30
  <div style="display:flex; align-items:center; gap:24px; min-height:96px;">
28
31
  ${statusVariants.map(
@@ -33,9 +36,10 @@ const renderStatusGroup = (opts: {
33
36
  .hoverStyle=${opts.hoverStyle}
34
37
  .disabled=${opts.disabled}
35
38
  .label=${opts.label}
36
- .isNested=${opts.isNested}
37
- .isLevel1=${opts.isLevel1}
38
- .isLevel2=${opts.isLevel2}
39
+ .description=${opts.description}
40
+ .level=${opts.level}
41
+ .expandable=${opts.expandable}
42
+ .expanded=${opts.expanded}
39
43
  ></obc-checkbox-item>`
40
44
  )}
41
45
  </div>
@@ -44,14 +48,7 @@ const renderStatusGroup = (opts: {
44
48
 
45
49
  const renderStateRow = (
46
50
  title: string,
47
- opts: {
48
- state: ObcCheckboxItemState;
49
- hoverStyle: ObcCheckboxItemHoverStyle;
50
- label: string;
51
- isNested: boolean;
52
- isLevel1: boolean;
53
- isLevel2: boolean;
54
- }
51
+ opts: RowOptions & {state: ObcCheckboxItemState}
55
52
  ) => html`
56
53
  <div style="display:flex; flex-direction:column; gap:8px; width:100%;">
57
54
  <div style="font-weight:600;">${title}</div>
@@ -62,13 +59,7 @@ const renderStateRow = (
62
59
  </div>
63
60
  `;
64
61
 
65
- const renderVariantRows = (opts: {
66
- hoverStyle: ObcCheckboxItemHoverStyle;
67
- label: string;
68
- isNested: boolean;
69
- isLevel1: boolean;
70
- isLevel2: boolean;
71
- }) => html`
62
+ const renderVariantRows = (opts: RowOptions) => html`
72
63
  <div style="display:flex; flex-direction:column; gap:20px; width:100%;">
73
64
  ${renderStateRow('Enabled', {
74
65
  ...opts,
@@ -88,7 +79,7 @@ const meta = {
88
79
  parameters: {
89
80
  layout: 'centered',
90
81
  actions: {
91
- handles: ['change'],
82
+ handles: ['change', 'expand-toggle'],
92
83
  },
93
84
  },
94
85
  render: (args, context) => {
@@ -98,9 +89,10 @@ const meta = {
98
89
  .disabled=${args.disabled}
99
90
  .hoverStyle=${args.hoverStyle}
100
91
  .label=${args.label}
101
- .isNested=${args.isNested}
102
- .isLevel1=${args.isLevel1}
103
- .isLevel2=${args.isLevel2}
92
+ .description=${args.description}
93
+ .level=${args.level}
94
+ .expandable=${args.expandable}
95
+ .expanded=${args.expanded}
104
96
  ></obc-checkbox-item>`;
105
97
 
106
98
  if (context.viewMode === 'docs') {
@@ -121,9 +113,10 @@ const meta = {
121
113
  .disabled=${args.disabled}
122
114
  .hoverStyle=${args.hoverStyle}
123
115
  .label=${args.label}
124
- .isNested=${args.isNested}
125
- .isLevel1=${args.isLevel1}
126
- .isLevel2=${args.isLevel2}
116
+ .description=${args.description}
117
+ .level=${args.level}
118
+ .expandable=${args.expandable}
119
+ .expanded=${args.expanded}
127
120
  ></obc-checkbox-item>
128
121
  </div>`;
129
122
  },
@@ -151,84 +144,76 @@ const meta = {
151
144
  name: 'Label',
152
145
  control: {type: 'text'},
153
146
  },
147
+ description: {
148
+ name: 'Description',
149
+ control: {type: 'text'},
150
+ },
151
+ level: {
152
+ name: 'Level',
153
+ control: {type: 'number', min: 0, max: 4, step: 1},
154
+ },
155
+ expandable: {
156
+ name: 'Expandable',
157
+ control: {type: 'boolean'},
158
+ },
159
+ expanded: {
160
+ name: 'Expanded',
161
+ control: {type: 'boolean'},
162
+ if: {arg: 'expandable', truthy: true},
163
+ },
154
164
  },
155
165
  } satisfies Meta<ObcCheckboxItem>;
156
166
 
157
167
  export default meta;
158
168
  type Story = StoryObj<ObcCheckboxItem>;
159
169
 
170
+ const defaultArgs = {
171
+ status: CheckboxStatus.unchecked,
172
+ state: ObcCheckboxItemState.enabled,
173
+ hoverStyle: ObcCheckboxItemHoverStyle.touchTarget,
174
+ label: 'Label',
175
+ description: '',
176
+ disabled: false,
177
+ level: 0,
178
+ expandable: false,
179
+ expanded: false,
180
+ };
181
+
160
182
  export const Playground: Story = {
161
- args: {
162
- status: CheckboxStatus.unchecked,
163
- state: ObcCheckboxItemState.enabled,
164
- hoverStyle: ObcCheckboxItemHoverStyle.touchTarget,
165
- label: 'Label',
166
- disabled: false,
167
- isNested: false,
168
- isLevel1: false,
169
- isLevel2: false,
170
- },
183
+ args: defaultArgs,
171
184
  };
172
185
 
173
186
  export const Nested: Story = {
174
- args: {
175
- status: CheckboxStatus.unchecked,
176
- state: ObcCheckboxItemState.enabled,
177
- hoverStyle: ObcCheckboxItemHoverStyle.touchTarget,
178
- label: 'Label',
179
- disabled: false,
180
- isNested: true,
181
- isLevel1: false,
182
- isLevel2: false,
183
- },
184
- render: (args) =>
185
- renderVariantRows({
186
- hoverStyle: args.hoverStyle,
187
- label: args.label,
188
- isNested: true,
189
- isLevel1: false,
190
- isLevel2: false,
191
- }),
187
+ args: {...defaultArgs, level: 1},
188
+ render: (args) => renderVariantRows(args),
192
189
  };
193
190
 
194
- export const Level1: Story = {
195
- args: {
196
- status: CheckboxStatus.unchecked,
197
- state: ObcCheckboxItemState.enabled,
198
- hoverStyle: ObcCheckboxItemHoverStyle.touchTarget,
199
- label: 'Label',
200
- disabled: false,
201
- isNested: true,
202
- isLevel1: true,
203
- isLevel2: false,
204
- },
205
- render: (args) =>
206
- renderVariantRows({
207
- hoverStyle: args.hoverStyle,
208
- label: args.label,
209
- isNested: true,
210
- isLevel1: true,
211
- isLevel2: false,
212
- }),
191
+ export const Expandable: Story = {
192
+ args: {...defaultArgs, level: 1, expandable: true},
193
+ render: (args) => html`
194
+ <div style="display:flex; flex-direction:column; gap:20px; width:100%;">
195
+ ${renderStateRow('Collapsed', {
196
+ ...args,
197
+ state: ObcCheckboxItemState.enabled,
198
+ expandable: true,
199
+ expanded: false,
200
+ })}
201
+ ${renderStateRow('Expanded', {
202
+ ...args,
203
+ state: ObcCheckboxItemState.enabled,
204
+ expandable: true,
205
+ expanded: true,
206
+ })}
207
+ </div>
208
+ `,
213
209
  };
214
210
 
215
211
  export const Level2: Story = {
216
- args: {
217
- status: CheckboxStatus.unchecked,
218
- state: ObcCheckboxItemState.enabled,
219
- hoverStyle: ObcCheckboxItemHoverStyle.touchTarget,
220
- label: 'Label',
221
- disabled: false,
222
- isNested: true,
223
- isLevel1: false,
224
- isLevel2: true,
225
- },
226
- render: (args) =>
227
- renderVariantRows({
228
- hoverStyle: args.hoverStyle,
229
- label: args.label,
230
- isNested: true,
231
- isLevel1: false,
232
- isLevel2: true,
233
- }),
212
+ args: {...defaultArgs, level: 2},
213
+ render: (args) => renderVariantRows(args),
214
+ };
215
+
216
+ export const WithDescription: Story = {
217
+ args: {...defaultArgs, description: 'Description'},
218
+ render: (args) => renderVariantRows(args),
234
219
  };