Skip to content

Commit f7d51f5

Browse files
authored
Add table settings (#7601)
2 parents 14fa824 + 7009776 commit f7d51f5

File tree

82 files changed

+1356
-411
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+1356
-411
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@use 'mixins' as *;
2+
3+
@mixin kol-popover-button-styles {
4+
@layer kol-component {
5+
.kol-popover-button {
6+
&__button {
7+
display: inline-block; // critical for floating UI to work correctly
8+
}
9+
10+
&__popover {
11+
border: 1px solid #000;
12+
margin: 0;
13+
padding: 0;
14+
}
15+
}
16+
}
17+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
@use './mixins' as *;
2+
3+
@mixin kol-table-settings-styles {
4+
@layer kol-component {
5+
.kol-table-settings {
6+
background: #fff;
7+
position: absolute;
8+
right: 0;
9+
top: 0;
10+
z-index: 1;
11+
12+
&__columns-container {
13+
margin-top: rem(16);
14+
max-height: rem(200);
15+
overflow: auto;
16+
}
17+
18+
&__columns {
19+
align-items: center;
20+
display: grid;
21+
gap: rem(8);
22+
grid-auto-rows: min-content;
23+
grid-template-columns: min-content 1fr rem(100) auto auto;
24+
overflow: hidden;
25+
}
26+
27+
&__column {
28+
display: contents;
29+
}
30+
}
31+
}
32+
}

packages/components/src/components/@shared/_kol-table-stateless-mixin.scss

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
1-
@use '../@shared/mixins' as *;
21
@use '../host-display-block' as *;
3-
@use '../tooltip/style.scss' as *;
2+
@use '../tooltip/style' as *;
3+
@use './kol-table-settings-mixin' as *;
4+
@use './mixins' as *;
45

56
@mixin kol-table-stateless-styles {
7+
@include kol-table-settings-styles;
8+
69
@layer kol-component {
710
.kol-table {
811
display: block;
912
font-size: rem(16);
10-
1113
max-width: 100%;
12-
overflow-x: auto;
13-
overflow-y: hidden;
14+
position: relative;
15+
16+
&__scroll-container {
17+
overflow-x: auto;
18+
overflow-y: hidden;
19+
}
1420

1521
&__table {
1622
width: 100%;
1723
}
1824

1925
&__caption {
2026
text-align: start;
27+
min-height: var(--a11y-min-size); // align with configuration button
28+
padding-right: var(--a11y-min-size);
2129
}
2230

2331
&__focus-element {
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
import type { JSX } from '@stencil/core';
2+
import { Component, h, Method, Prop, State, Watch } from '@stencil/core';
3+
import { KolButtonWcTag } from '../../core/component-names';
4+
import { alignFloatingElements } from '../../utils/align-floating-elements';
5+
import type { PopoverButtonProps, PopoverButtonStates } from '../../schema/components/popover-button';
6+
import type {
7+
AccessKeyPropType,
8+
AlternativeButtonLinkRolePropType,
9+
AriaDescriptionPropType,
10+
ButtonCallbacksPropType,
11+
ButtonTypePropType,
12+
ButtonVariantPropType,
13+
CustomClassPropType,
14+
IconsPropType,
15+
LabelWithExpertSlotPropType,
16+
PopoverAlignPropType,
17+
ShortKeyPropType,
18+
StencilUnknown,
19+
Stringified,
20+
SyncValueBySelectorPropType,
21+
TooltipAlignPropType,
22+
} from '../../schema';
23+
import { validatePopoverAlign } from '../../schema';
24+
25+
/**
26+
* @slot - The popover content.
27+
*/
28+
@Component({
29+
tag: 'kol-popover-button-wc',
30+
shadow: false,
31+
})
32+
// class implementing PopoverButtonProps and not API because we don't want to repeat the entire state and validation for button props
33+
export class KolPopoverButton implements PopoverButtonProps {
34+
private refButton?: HTMLKolButtonWcElement;
35+
private refPopover?: HTMLDivElement;
36+
37+
@State() public state: PopoverButtonStates = {
38+
_label: '',
39+
_popoverAlign: 'bottom',
40+
};
41+
@State() private justClosed = false;
42+
43+
/**
44+
* Hides the popover programmatically by calling the native hidePopover method.
45+
*/
46+
@Method()
47+
// eslint-disable-next-line @typescript-eslint/require-await
48+
public async hidePopover() {
49+
void this.refPopover?.hidePopover();
50+
}
51+
52+
/* Regarding type issue see https://github.com/microsoft/TypeScript/issues/54864 */
53+
private handleBeforeToggle(event: Event) {
54+
if ((event as ToggleEvent).newState === 'closed') {
55+
this.justClosed = true;
56+
57+
setTimeout(() => {
58+
// Reset the flag after the event loop tick.
59+
this.justClosed = false;
60+
}, 10); // timeout of 0 should be sufficient but doesn't work in Safari Mobile (needs further investigation).
61+
} else if (this.refPopover) {
62+
/**
63+
* Avoid "flicker" by hiding the element until the position is set in the `toggle` event handler. `alignFloatingElements` is responsible for setting the visibility back to 'visible'.
64+
*/
65+
this.refPopover.style.visibility = 'hidden';
66+
}
67+
}
68+
69+
private handleToggle(event: Event) {
70+
if ((event as ToggleEvent).newState === 'open' && this.refPopover && this.refButton) {
71+
void alignFloatingElements({
72+
align: this.state._popoverAlign,
73+
floatingElement: this.refPopover,
74+
referenceElement: this.refButton,
75+
});
76+
}
77+
}
78+
79+
private handleButtonClick() {
80+
// If the popover was just closed by native behavior, do nothing (and let it stay closed).
81+
if (!this.justClosed) {
82+
this.refPopover?.togglePopover();
83+
}
84+
}
85+
86+
public componentDidRender() {
87+
this.refPopover?.addEventListener('toggle', this.handleToggle.bind(this));
88+
this.refPopover?.addEventListener('beforetoggle', this.handleBeforeToggle.bind(this));
89+
}
90+
91+
public disconnectedCallback() {
92+
this.refPopover?.removeEventListener('toggle', this.handleToggle.bind(this));
93+
this.refPopover?.removeEventListener('beforetoggle', this.handleBeforeToggle.bind(this));
94+
}
95+
96+
public render(): JSX.Element {
97+
return (
98+
<div class="kol-popover-button">
99+
<KolButtonWcTag
100+
_accessKey={this._accessKey}
101+
_ariaControls={this._ariaControls}
102+
_ariaDescription={this._ariaDescription}
103+
_ariaExpanded={this._ariaExpanded}
104+
_ariaSelected={this._ariaSelected}
105+
_customClass={this._customClass}
106+
_disabled={this._disabled}
107+
_hideLabel={this._hideLabel}
108+
_icons={this._icons}
109+
_id={this._id}
110+
_label={this._label}
111+
_name={this._name}
112+
_on={this._on}
113+
_role={this._role}
114+
_shortKey={this._shortKey}
115+
_syncValueBySelector={this._syncValueBySelector}
116+
_tabIndex={this._tabIndex}
117+
_tooltipAlign={this._tooltipAlign}
118+
_type={this._type}
119+
_value={this._value}
120+
_variant={this._variant}
121+
data-testid="popover-button"
122+
class="kol-popover-button__button"
123+
ref={(element) => (this.refButton = element)}
124+
onClick={this.handleButtonClick.bind(this)}
125+
>
126+
<slot name="expert" slot="expert"></slot>
127+
</KolButtonWcTag>
128+
129+
<div ref={(element) => (this.refPopover = element)} data-testid="popover-content" popover="auto" id="popover" class="kol-popover-button__popover">
130+
<slot />
131+
</div>
132+
</div>
133+
);
134+
}
135+
136+
/**
137+
* Defines which key combination can be used to trigger or focus the interactive element of the component.
138+
*/
139+
@Prop() public _accessKey?: AccessKeyPropType;
140+
141+
/**
142+
* Defines which elements are controlled by this component. (https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-controls)
143+
*/
144+
@Prop() public _ariaControls?: string;
145+
146+
/**
147+
* Defines the value for the aria-description attribute.
148+
*/
149+
@Prop() public _ariaDescription?: AriaDescriptionPropType;
150+
151+
/**
152+
* Defines whether the interactive element of the component expanded something. (https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded)
153+
*/
154+
@Prop() public _ariaExpanded?: boolean;
155+
156+
/**
157+
* Defines whether the interactive element of the component is selected (e.g. role=tab). (https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-selected)
158+
*/
159+
@Prop() public _ariaSelected?: boolean;
160+
161+
/**
162+
* Defines the custom class attribute if _variant="custom" is set.
163+
*/
164+
@Prop() public _customClass?: CustomClassPropType;
165+
166+
/**
167+
* Makes the element not focusable and ignore all events.
168+
*/
169+
@Prop() public _disabled?: boolean = false;
170+
171+
/**
172+
* Hides the caption by default and displays the caption text with a tooltip when the
173+
* interactive element is focused or the mouse is over it.
174+
* @TODO: Change type back to `HideLabelPropType` after Stencil#4663 has been resolved.
175+
*/
176+
@Prop() public _hideLabel?: boolean = false;
177+
178+
/**
179+
* Defines the icon classnames (e.g. `_icons="fa-solid fa-user"`).
180+
*/
181+
@Prop() public _icons?: IconsPropType;
182+
183+
/**
184+
* Defines the internal ID of the primary component element.
185+
*/
186+
@Prop() public _id?: string;
187+
188+
/**
189+
* Defines the visible or semantic label of the component (e.g. aria-label, label, headline, caption, summary, etc.). Set to `false` to enable the expert slot.
190+
*/
191+
@Prop() public _label!: LabelWithExpertSlotPropType;
192+
193+
/**
194+
* Defines the technical name of an input field.
195+
*/
196+
@Prop() public _name?: string;
197+
198+
/**
199+
* Defines the callback functions for button events.
200+
*/
201+
@Prop() public _on?: ButtonCallbacksPropType<StencilUnknown>;
202+
203+
/**
204+
* Defines where to show the Popover preferably: top, right, bottom or left.
205+
*/
206+
@Prop() public _popoverAlign?: PopoverAlignPropType = 'bottom';
207+
208+
/**
209+
* Defines the role of the components primary element.
210+
*/
211+
@Prop() public _role?: AlternativeButtonLinkRolePropType;
212+
213+
/**
214+
* Adds a visual short key hint to the component.
215+
*/
216+
@Prop() public _shortKey?: ShortKeyPropType;
217+
218+
/**
219+
* Selector for synchronizing the value with another input element.
220+
* @internal
221+
*/
222+
@Prop() public _syncValueBySelector?: SyncValueBySelectorPropType;
223+
224+
/**
225+
* Defines which tab-index the primary element of the component has. (https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex)
226+
*/
227+
@Prop() public _tabIndex?: number;
228+
229+
/**
230+
* Defines where to show the Tooltip preferably: top, right, bottom or left.
231+
*/
232+
@Prop() public _tooltipAlign?: TooltipAlignPropType = 'top';
233+
234+
/**
235+
* Defines either the type of the component or of the components interactive element.
236+
*/
237+
@Prop() public _type?: ButtonTypePropType = 'button';
238+
239+
/**
240+
* Defines the value that the button emits on click.
241+
*/
242+
@Prop() public _value?: Stringified<StencilUnknown>;
243+
244+
/**
245+
* Defines which variant should be used for presentation.
246+
*/
247+
@Prop() public _variant?: ButtonVariantPropType = 'normal';
248+
249+
@Watch('_popoverAlign')
250+
public validatePopoverAlign(value?: PopoverAlignPropType): void {
251+
validatePopoverAlign(this, value);
252+
}
253+
254+
public componentWillLoad() {
255+
this.validatePopoverAlign(this._popoverAlign);
256+
}
257+
}

0 commit comments

Comments
 (0)