@reliability-design/web 1.0.2 → 1.0.6
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/dist/components/rel-accordion/README.md +132 -0
- package/dist/components/rel-accordion/rel-accordion.ts +61 -29
- package/dist/components/rel-alert/README.md +141 -0
- package/dist/components/rel-alert/rel-alert.ts +110 -67
- package/dist/components/rel-avatar/README.md +119 -0
- package/dist/components/rel-avatar/rel-avatar.ts +8 -15
- package/dist/components/rel-badge/README.md +86 -0
- package/dist/components/rel-badge/rel-badge.ts +28 -21
- package/dist/components/rel-breadcrumb/README.md +102 -0
- package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +24 -18
- package/dist/components/rel-button/README.md +130 -0
- package/dist/components/rel-button/rel-button.ts +39 -59
- package/dist/components/rel-calendar/README.md +109 -0
- package/dist/components/rel-calendar/index.ts +1 -0
- package/dist/components/rel-calendar/rel-calendar.ts +467 -0
- package/dist/components/rel-card/README.md +94 -0
- package/dist/components/rel-card/rel-card.ts +21 -11
- package/dist/components/rel-cardmedia/README.md +127 -0
- package/dist/components/rel-cardmedia/rel-cardmedia.ts +22 -18
- package/dist/components/rel-carousel/README.md +166 -0
- package/dist/components/rel-carousel/index.ts +1 -0
- package/dist/components/rel-carousel/rel-carousel.ts +469 -0
- package/dist/components/rel-chart/README.md +286 -0
- package/dist/components/rel-chart/index.ts +1 -0
- package/dist/components/rel-chart/rel-chart.ts +736 -0
- package/dist/components/rel-checkbox/README.md +77 -0
- package/dist/components/rel-checkbox/rel-checkbox.ts +36 -45
- package/dist/components/rel-chip/README.md +114 -0
- package/dist/components/rel-chip/rel-chip.ts +47 -122
- package/dist/components/rel-container/README.md +99 -0
- package/dist/components/rel-container/rel-container.ts +1 -6
- package/dist/components/rel-date-picker/README.md +253 -0
- package/dist/components/rel-date-picker/index.ts +1 -0
- package/dist/components/rel-date-picker/rel-date-picker.ts +916 -0
- package/dist/components/rel-divider/README.md +100 -0
- package/dist/components/rel-divider/rel-divider.ts +37 -37
- package/dist/components/rel-drawer/README.md +200 -0
- package/dist/components/rel-drawer/index.ts +1 -0
- package/dist/components/rel-drawer/rel-drawer.ts +621 -0
- package/dist/components/rel-kbd/README.md +151 -0
- package/dist/components/rel-kbd/rel-kbd.ts +118 -0
- package/dist/components/rel-layout/README.md +88 -0
- package/dist/components/rel-layout/rel-layout.ts +12 -14
- package/dist/components/rel-menu/README.md +151 -0
- package/dist/components/rel-menu/rel-menu.ts +18 -10
- package/dist/components/rel-menubar/README.md +329 -0
- package/dist/components/rel-menubar/index.ts +2 -0
- package/dist/components/rel-menubar/rel-menubar-menu.ts +16 -0
- package/dist/components/rel-menubar/rel-menubar.ts +576 -0
- package/dist/components/rel-nav-menu/README.md +289 -0
- package/dist/components/rel-nav-menu/index.ts +3 -0
- package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +143 -0
- package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +53 -0
- package/dist/components/rel-nav-menu/rel-nav-menu.ts +331 -0
- package/dist/components/rel-navbar/README.md +126 -0
- package/dist/components/rel-navbar/rel-navbar.ts +91 -0
- package/dist/components/rel-otp/README.md +440 -0
- package/dist/components/rel-otp/index.ts +1 -0
- package/dist/components/rel-otp/rel-otp.ts +504 -0
- package/dist/components/rel-pagination/README.md +410 -0
- package/dist/components/rel-pagination/index.ts +1 -0
- package/dist/components/rel-pagination/rel-pagination.ts +376 -0
- package/dist/components/rel-popover/README.md +568 -0
- package/dist/components/rel-popover/index.ts +2 -0
- package/dist/components/rel-popover/rel-popover-content.ts +55 -0
- package/dist/components/rel-popover/rel-popover.ts +327 -0
- package/dist/components/rel-progress/README.md +110 -0
- package/dist/components/rel-progress/rel-progress.ts +58 -20
- package/dist/components/rel-quote-page/README.md +166 -0
- package/dist/components/rel-quote-page/rel-quote-page.ts +816 -0
- package/dist/components/rel-radio/README.md +120 -0
- package/dist/components/rel-radio/rel-radio.ts +41 -73
- package/dist/components/rel-resizable/README.md +140 -0
- package/dist/components/rel-resizable/index.ts +3 -0
- package/dist/components/rel-resizable/rel-resizable-group.ts +374 -0
- package/dist/components/rel-resizable/rel-resizable-handle.ts +149 -0
- package/dist/components/rel-resizable/rel-resizable-panel.ts +47 -0
- package/dist/components/rel-segmented-button/README.md +141 -0
- package/dist/components/rel-segmented-button/rel-segmented-button.ts +18 -13
- package/dist/components/rel-select/README.md +107 -0
- package/dist/components/rel-select/rel-select.ts +14 -14
- package/dist/components/rel-sheet/README.md +224 -0
- package/dist/components/rel-sheet/rel-sheet.ts +683 -0
- package/dist/components/rel-sidebar/README.md +209 -0
- package/dist/components/rel-sidebar/rel-sidebar.ts +1158 -0
- package/dist/components/rel-slider/README.md +135 -0
- package/dist/components/rel-slider/rel-slider.ts +19 -7
- package/dist/components/rel-snackbar/README.md +134 -0
- package/dist/components/rel-snackbar/rel-snackbar.ts +73 -2
- package/dist/components/rel-stepper/README.md +160 -0
- package/dist/components/rel-stepper/rel-stepper.ts +29 -8
- package/dist/components/rel-switch/README.md +102 -0
- package/dist/components/rel-switch/rel-switch.ts +22 -11
- package/dist/components/rel-tab/README.md +163 -0
- package/dist/components/rel-tab/rel-tab.ts +46 -22
- package/dist/components/rel-table/README.md +178 -0
- package/dist/components/rel-table/rel-table-body.ts +16 -0
- package/dist/components/rel-table/rel-table-caption.ts +22 -0
- package/dist/components/rel-table/rel-table-cell.ts +49 -0
- package/dist/components/rel-table/rel-table-footer.ts +18 -0
- package/dist/components/rel-table/rel-table-head.ts +33 -0
- package/dist/components/rel-table/rel-table-header.ts +16 -0
- package/dist/components/rel-table/rel-table-row.ts +32 -0
- package/dist/components/rel-table/rel-table.ts +47 -0
- package/dist/components/rel-textfield/README.md +90 -0
- package/dist/components/rel-textfield/rel-textfield.ts +37 -21
- package/dist/components/rel-toast/README.md +148 -0
- package/dist/components/rel-toast/rel-toast.ts +32 -14
- package/dist/components/rel-tooltip/README.md +103 -0
- package/dist/components/rel-tooltip/rel-tooltip.ts +9 -9
- package/dist/index.d.mts +846 -7
- package/dist/index.d.ts +846 -7
- package/dist/index.js +10860 -1803
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10820 -1809
- package/dist/index.mjs.map +1 -1
- package/dist/styles/vars.css +293 -183
- package/dist/vars-ITL2K3KO.css +294 -0
- package/package.json +2 -2
- package/dist/components/rel-accordion/rel-accordion.stories.ts +0 -313
- package/dist/components/rel-alert/rel-alert.stories.ts +0 -412
- package/dist/components/rel-avatar/rel-avatar.stories.ts +0 -327
- package/dist/components/rel-badge/rel-badge.stories.ts +0 -350
- package/dist/components/rel-breadcrumb/rel-breadcrumb.stories.ts +0 -306
- package/dist/components/rel-button/rel-button.stories.ts +0 -356
- package/dist/components/rel-card/rel-card.stories.ts +0 -299
- package/dist/components/rel-cardmedia/rel-cardmedia.stories.ts +0 -368
- package/dist/components/rel-checkbox/rel-checkbox.stories.ts +0 -414
- package/dist/components/rel-chip/rel-chip.stories.ts +0 -552
- package/dist/components/rel-container/rel-container.stories.ts +0 -239
- package/dist/components/rel-divider/rel-divider.stories.ts +0 -229
- package/dist/components/rel-layout/rel-layout.stories.ts +0 -713
- package/dist/components/rel-menu/rel-menu.stories.ts +0 -910
- package/dist/components/rel-progress/rel-progress.stories.ts +0 -817
- package/dist/components/rel-radio/rel-radio.stories.ts +0 -1048
- package/dist/components/rel-segmented-button/rel-segmented-button.stories.ts +0 -1079
- package/dist/components/rel-select/rel-select.stories.ts +0 -1201
- package/dist/components/rel-slider/rel-slider.stories.ts +0 -730
- package/dist/components/rel-snackbar/rel-snackbar.stories.ts +0 -808
- package/dist/components/rel-stepper/rel-stepper.stories.ts +0 -752
- package/dist/components/rel-switch/rel-switch.stories.ts +0 -441
- package/dist/components/rel-tab/rel-tab.stories.ts +0 -492
- package/dist/components/rel-textfield/rel-textfield.stories.ts +0 -710
- package/dist/components/rel-toast/rel-toast.stories.ts +0 -394
- package/dist/components/rel-tooltip/rel-tooltip.stories.ts +0 -364
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# rel-kbd
|
|
2
|
+
|
|
3
|
+
A keyboard key/shortcut pill component for displaying keyboard shortcuts and key combinations in a visually consistent way.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<!-- Basic usage -->
|
|
9
|
+
<rel-kbd>K</rel-kbd>
|
|
10
|
+
|
|
11
|
+
<!-- Keyboard shortcut combination -->
|
|
12
|
+
<rel-kbd>Ctrl</rel-kbd> + <rel-kbd>K</rel-kbd>
|
|
13
|
+
|
|
14
|
+
<!-- With variants -->
|
|
15
|
+
<rel-kbd variant="muted">⌘</rel-kbd>
|
|
16
|
+
<rel-kbd variant="default">Shift</rel-kbd>
|
|
17
|
+
|
|
18
|
+
<!-- Different sizes -->
|
|
19
|
+
<rel-kbd size="sm">Esc</rel-kbd>
|
|
20
|
+
<rel-kbd size="md">Enter</rel-kbd>
|
|
21
|
+
<rel-kbd size="lg">Space</rel-kbd>
|
|
22
|
+
|
|
23
|
+
<!-- Pill shape -->
|
|
24
|
+
<rel-kbd pill>R</rel-kbd>
|
|
25
|
+
|
|
26
|
+
<!-- Inset (pressed) appearance -->
|
|
27
|
+
<rel-kbd inset>Tab</rel-kbd>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## API
|
|
31
|
+
|
|
32
|
+
### Properties
|
|
33
|
+
|
|
34
|
+
| Property | Type | Default | Description |
|
|
35
|
+
|----------|------|---------|-------------|
|
|
36
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Controls the size of the kbd element |
|
|
37
|
+
| `variant` | `"default" \| "muted"` | `"default"` | Visual style variant |
|
|
38
|
+
| `pill` | `boolean` | `false` | When true, renders with full rounded corners |
|
|
39
|
+
| `inset` | `boolean` | `false` | When true, renders with pressed/inset appearance |
|
|
40
|
+
|
|
41
|
+
### Slots
|
|
42
|
+
|
|
43
|
+
| Slot | Description |
|
|
44
|
+
|------|-------------|
|
|
45
|
+
| (default) | The keyboard key label or character |
|
|
46
|
+
|
|
47
|
+
### CSS Custom Properties
|
|
48
|
+
|
|
49
|
+
The component uses design tokens from the Reliability Design System:
|
|
50
|
+
|
|
51
|
+
#### Colors
|
|
52
|
+
- `--rel-colors-gray-light` - Default background
|
|
53
|
+
- `--rel-colors-gray-background` - Muted and inset backgrounds
|
|
54
|
+
- `--rel-colors-gray-heading` - Default text color
|
|
55
|
+
- `--rel-colors-gray-placeholder` - Muted text color
|
|
56
|
+
- `--rel-colors-gray-border` - Default border
|
|
57
|
+
- `--rel-colors-gray-divider` - Muted border
|
|
58
|
+
|
|
59
|
+
#### Typography
|
|
60
|
+
- `--rel-fontFamilies-primary` - Font family (Poppins)
|
|
61
|
+
- `--rel-fontWeights-medium` - Font weight (500)
|
|
62
|
+
- `--rel-fontSizes-xs` - Small size font
|
|
63
|
+
- `--rel-fontSizes-sm` - Medium size font
|
|
64
|
+
- `--rel-fontSizes-md` - Large size font
|
|
65
|
+
|
|
66
|
+
#### Spacing
|
|
67
|
+
- `--rel-spacing-space-3xs` (2px)
|
|
68
|
+
- `--rel-spacing-space-2xs` (4px)
|
|
69
|
+
- `--rel-spacing-space-xs` (8px)
|
|
70
|
+
- `--rel-spacing-space-sm` (12px)
|
|
71
|
+
- `--rel-spacing-space-md` (16px)
|
|
72
|
+
|
|
73
|
+
#### Borders
|
|
74
|
+
- `--rel-borders-width-stroke-100` (1px)
|
|
75
|
+
- `--rel-borders-radius-border-radius-100` (2px)
|
|
76
|
+
- `--rel-borders-radius-border-radius-200` (8px)
|
|
77
|
+
- `--rel-borders-radius-border-radius-500` (1000px - pill shape)
|
|
78
|
+
|
|
79
|
+
## Examples
|
|
80
|
+
|
|
81
|
+
### Search Shortcut
|
|
82
|
+
```html
|
|
83
|
+
<p>Press <rel-kbd>Ctrl</rel-kbd> + <rel-kbd>K</rel-kbd> to search</p>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Mac Shortcut
|
|
87
|
+
```html
|
|
88
|
+
<p>Press <rel-kbd variant="muted">⌘</rel-kbd> + <rel-kbd>Shift</rel-kbd> + <rel-kbd pill>R</rel-kbd> to reload</p>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Multiple Sizes
|
|
92
|
+
```html
|
|
93
|
+
<div style="display: flex; gap: 8px; align-items: center;">
|
|
94
|
+
<rel-kbd size="sm">S</rel-kbd>
|
|
95
|
+
<rel-kbd size="md">M</rel-kbd>
|
|
96
|
+
<rel-kbd size="lg">L</rel-kbd>
|
|
97
|
+
</div>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Pressed State
|
|
101
|
+
```html
|
|
102
|
+
<p>Hold <rel-kbd inset>Space</rel-kbd> to preview</p>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Accessibility
|
|
106
|
+
|
|
107
|
+
- Uses semantic `<kbd>` HTML element for proper semantics
|
|
108
|
+
- `role="presentation"` is set to avoid redundant announcements
|
|
109
|
+
- Non-interactive by default (no tabindex)
|
|
110
|
+
- Text content is fully accessible to screen readers
|
|
111
|
+
- Inherits text color that maintains sufficient contrast ratios
|
|
112
|
+
|
|
113
|
+
## Styling Notes
|
|
114
|
+
|
|
115
|
+
### Default Appearance
|
|
116
|
+
- Subtle background with light border
|
|
117
|
+
- Small inset highlight shadow for raised appearance
|
|
118
|
+
- Monospaced font weight for technical look
|
|
119
|
+
|
|
120
|
+
### Muted Variant
|
|
121
|
+
- Lower contrast for secondary shortcuts
|
|
122
|
+
- Softer colors and reduced shadow
|
|
123
|
+
|
|
124
|
+
### Pill Modifier
|
|
125
|
+
- Fully rounded corners using border-radius-500 token
|
|
126
|
+
- Ideal for single character keys
|
|
127
|
+
|
|
128
|
+
### Inset Modifier
|
|
129
|
+
- Inverted shadow for pressed/active appearance
|
|
130
|
+
- Slight vertical translation for depth effect
|
|
131
|
+
- Darker background to indicate pressed state
|
|
132
|
+
|
|
133
|
+
## Dark Mode Support
|
|
134
|
+
|
|
135
|
+
The component automatically supports dark mode when design tokens are configured with dark mode variants, as it exclusively uses CSS custom properties.
|
|
136
|
+
|
|
137
|
+
## Browser Support
|
|
138
|
+
|
|
139
|
+
Compatible with all modern browsers that support:
|
|
140
|
+
- Web Components
|
|
141
|
+
- CSS Custom Properties
|
|
142
|
+
- Shadow DOM
|
|
143
|
+
|
|
144
|
+
## Framework Integration
|
|
145
|
+
|
|
146
|
+
Works seamlessly with:
|
|
147
|
+
- Vanilla JavaScript
|
|
148
|
+
- Angular
|
|
149
|
+
- React (via wrapper)
|
|
150
|
+
- Vue
|
|
151
|
+
- Any framework that supports Web Components
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
import { customElement, property } from "lit/decorators.js";
|
|
3
|
+
|
|
4
|
+
@customElement("rel-kbd")
|
|
5
|
+
export class RelKbd extends LitElement {
|
|
6
|
+
@property({ type: String, reflect: true })
|
|
7
|
+
size: "sm" | "md" | "lg" = "md";
|
|
8
|
+
|
|
9
|
+
@property({ type: String, reflect: true })
|
|
10
|
+
variant: "default" | "muted" = "default";
|
|
11
|
+
|
|
12
|
+
@property({ type: Boolean, reflect: true })
|
|
13
|
+
pill = false;
|
|
14
|
+
|
|
15
|
+
@property({ type: Boolean, reflect: true })
|
|
16
|
+
inset = false;
|
|
17
|
+
|
|
18
|
+
static styles = css`
|
|
19
|
+
:host {
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
kbd {
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
font-family: var(--rel-fontFamilies-primary);
|
|
28
|
+
font-weight: var(--rel-fontWeights-medium);
|
|
29
|
+
white-space: nowrap;
|
|
30
|
+
user-select: none;
|
|
31
|
+
transition: all 0.15s ease;
|
|
32
|
+
line-height: 1;
|
|
33
|
+
vertical-align: middle;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Size variants */
|
|
37
|
+
.kbd-sm {
|
|
38
|
+
font-size: var(--rel-fontSizes-xs);
|
|
39
|
+
padding: var(--rel-spacing-space-3xs) var(--rel-spacing-space-xs);
|
|
40
|
+
min-width: 20px;
|
|
41
|
+
height: 20px;
|
|
42
|
+
border-radius: var(--rel-borders-radius-border-radius-100);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.kbd-md {
|
|
46
|
+
font-size: var(--rel-fontSizes-sm);
|
|
47
|
+
padding: var(--rel-spacing-space-2xs) var(--rel-spacing-space-sm);
|
|
48
|
+
min-width: 24px;
|
|
49
|
+
height: 24px;
|
|
50
|
+
border-radius: var(--rel-borders-radius-border-radius-100);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.kbd-lg {
|
|
54
|
+
font-size: var(--rel-fontSizes-md);
|
|
55
|
+
padding: var(--rel-spacing-space-xs) var(--rel-spacing-space-md);
|
|
56
|
+
min-width: 32px;
|
|
57
|
+
height: 32px;
|
|
58
|
+
border-radius: var(--rel-borders-radius-border-radius-200);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Variant: default */
|
|
62
|
+
.kbd-default {
|
|
63
|
+
background: var(--rel-colors-gray-light);
|
|
64
|
+
color: var(--rel-colors-gray-heading);
|
|
65
|
+
border: var(--rel-borders-width-stroke-100) solid var(--rel-colors-gray-border);
|
|
66
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px 0 0 rgba(255, 255, 255, 0.5) inset;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Variant: muted */
|
|
70
|
+
.kbd-muted {
|
|
71
|
+
background: var(--rel-surface-secondary, #fafafa);
|
|
72
|
+
color: var(--rel-colors-gray-placeholder);
|
|
73
|
+
border: var(--rel-borders-width-stroke-100) solid var(--rel-colors-gray-divider);
|
|
74
|
+
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.03);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Pill modifier */
|
|
78
|
+
:host([pill]) .kbd-sm {
|
|
79
|
+
border-radius: var(--rel-borders-radius-border-radius-500);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
:host([pill]) .kbd-md {
|
|
83
|
+
border-radius: var(--rel-borders-radius-border-radius-500);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
:host([pill]) .kbd-lg {
|
|
87
|
+
border-radius: var(--rel-borders-radius-border-radius-500);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Inset modifier - pressed appearance */
|
|
91
|
+
:host([inset]) kbd {
|
|
92
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset, 0 1px 0 0 rgba(0, 0, 0, 0.05);
|
|
93
|
+
transform: translateY(1px);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
:host([inset]) .kbd-default {
|
|
97
|
+
background: var(--rel-surface-secondary, #fafafa);
|
|
98
|
+
border-color: var(--rel-colors-gray-divider);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
:host([inset]) .kbd-muted {
|
|
102
|
+
background: var(--rel-colors-gray-divider);
|
|
103
|
+
border-color: var(--rel-colors-gray-border);
|
|
104
|
+
}
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
private get classes() {
|
|
108
|
+
return ["kbd", `kbd-${this.size}`, `kbd-${this.variant}`].join(" ");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
render() {
|
|
112
|
+
return html`
|
|
113
|
+
<kbd class="${this.classes}" role="presentation">
|
|
114
|
+
<slot></slot>
|
|
115
|
+
</kbd>
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# rel-layout
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
A responsive CSS Grid layout component with automatic breakpoint handling. Provides a configurable grid with customizable column count and gap, automatically adapting to smaller viewports when `responsive` is enabled.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
```html
|
|
8
|
+
<!-- Basic 4-column grid -->
|
|
9
|
+
<rel-layout>
|
|
10
|
+
<div>Item 1</div>
|
|
11
|
+
<div>Item 2</div>
|
|
12
|
+
<div>Item 3</div>
|
|
13
|
+
<div>Item 4</div>
|
|
14
|
+
<div>Item 5</div>
|
|
15
|
+
<div>Item 6</div>
|
|
16
|
+
</rel-layout>
|
|
17
|
+
|
|
18
|
+
<!-- Custom columns and gap -->
|
|
19
|
+
<rel-layout columns="3" gap="24px">
|
|
20
|
+
<div>Column 1</div>
|
|
21
|
+
<div>Column 2</div>
|
|
22
|
+
<div>Column 3</div>
|
|
23
|
+
</rel-layout>
|
|
24
|
+
|
|
25
|
+
<!-- Fixed layout (non-responsive) -->
|
|
26
|
+
<rel-layout columns="2" gap="16px" responsive="false">
|
|
27
|
+
<div>Always 2 columns</div>
|
|
28
|
+
<div>Even on mobile</div>
|
|
29
|
+
</rel-layout>
|
|
30
|
+
|
|
31
|
+
<!-- Large gap with 6 columns -->
|
|
32
|
+
<rel-layout columns="6" gap="2rem">
|
|
33
|
+
<div>Item 1</div>
|
|
34
|
+
<div>Item 2</div>
|
|
35
|
+
<div>Item 3</div>
|
|
36
|
+
<div>Item 4</div>
|
|
37
|
+
<div>Item 5</div>
|
|
38
|
+
<div>Item 6</div>
|
|
39
|
+
</rel-layout>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
### Attributes/Properties
|
|
45
|
+
| Name | Type | Default | Description |
|
|
46
|
+
|------|------|---------|-------------|
|
|
47
|
+
| `columns` | `number` | `4` | Number of columns in the grid |
|
|
48
|
+
| `gap` | `string` | `"1rem"` | CSS gap value (supports any CSS length unit) |
|
|
49
|
+
| `responsive` (reflected) | `boolean` | `true` | Enable automatic responsive breakpoints |
|
|
50
|
+
|
|
51
|
+
## Events
|
|
52
|
+
None.
|
|
53
|
+
|
|
54
|
+
## Slots
|
|
55
|
+
| Slot | Description |
|
|
56
|
+
|------|-------------|
|
|
57
|
+
| (default) | Grid items (any HTML elements) |
|
|
58
|
+
|
|
59
|
+
## CSS Parts
|
|
60
|
+
None exposed.
|
|
61
|
+
|
|
62
|
+
## Tokens / CSS Variables
|
|
63
|
+
|
|
64
|
+
### Semantic Tokens
|
|
65
|
+
- `--rel-fontFamilies-primary` - Font family
|
|
66
|
+
|
|
67
|
+
## Accessibility
|
|
68
|
+
- Uses standard CSS Grid, which is accessible by default
|
|
69
|
+
- Ensure grid items contain proper semantic HTML
|
|
70
|
+
|
|
71
|
+
### Keyboard Interactions
|
|
72
|
+
- Standard browser navigation through grid items
|
|
73
|
+
|
|
74
|
+
### Focus Behavior
|
|
75
|
+
- No specific focus handling (relies on slotted content)
|
|
76
|
+
|
|
77
|
+
## Notes / Edge Cases
|
|
78
|
+
- **Responsive breakpoints** (only when `responsive` is true):
|
|
79
|
+
- **≤1024px**: 3 columns
|
|
80
|
+
- **≤768px**: 2 columns
|
|
81
|
+
- **≤480px**: 1 column
|
|
82
|
+
- The `responsive` attribute is reflected, so CSS can target `:host([responsive])`
|
|
83
|
+
- Responsive styles use `!important` to override inline column count
|
|
84
|
+
- If `responsive` is set to `false`, the grid maintains the specified column count at all viewport sizes
|
|
85
|
+
- The grid is `display: grid` with `width: 100%`
|
|
86
|
+
- The `columns` and `gap` properties are applied as inline styles for maximum flexibility
|
|
87
|
+
- The component is `display: block` and `width: 100%`
|
|
88
|
+
- Grid items do not have any default styling—you must style them yourself
|
|
@@ -3,11 +3,12 @@ import { customElement, property } from "lit/decorators.js";
|
|
|
3
3
|
|
|
4
4
|
@customElement("rel-layout")
|
|
5
5
|
export class RelLayout extends LitElement {
|
|
6
|
-
@property({ type: String }) gap
|
|
6
|
+
@property({ type: String }) gap = "1rem";
|
|
7
7
|
|
|
8
|
-
@property({ type: Number }) columns
|
|
8
|
+
@property({ type: Number }) columns = 4;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// 🔥 IMPORTANT: reflect so CSS selectors work
|
|
11
|
+
@property({ type: Boolean, reflect: true }) responsive = true;
|
|
11
12
|
|
|
12
13
|
static styles = css`
|
|
13
14
|
:host {
|
|
@@ -21,11 +22,7 @@ export class RelLayout extends LitElement {
|
|
|
21
22
|
font-family: var(--rel-fontFamilies-primary);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
/* Responsive breakpoints
|
|
25
|
-
:host([responsive]) .layout-grid {
|
|
26
|
-
/* Default: use columns property */
|
|
27
|
-
}
|
|
28
|
-
|
|
25
|
+
/* Responsive breakpoints — only when attribute exists */
|
|
29
26
|
@media (max-width: 1024px) {
|
|
30
27
|
:host([responsive]) .layout-grid {
|
|
31
28
|
grid-template-columns: repeat(3, 1fr) !important;
|
|
@@ -46,13 +43,14 @@ export class RelLayout extends LitElement {
|
|
|
46
43
|
`;
|
|
47
44
|
|
|
48
45
|
render() {
|
|
49
|
-
const gridStyle = `
|
|
50
|
-
gap: ${this.gap};
|
|
51
|
-
grid-template-columns: repeat(${this.columns}, 1fr);
|
|
52
|
-
`;
|
|
53
|
-
|
|
54
46
|
return html`
|
|
55
|
-
<div
|
|
47
|
+
<div
|
|
48
|
+
class="layout-grid"
|
|
49
|
+
style="
|
|
50
|
+
gap: ${this.gap};
|
|
51
|
+
grid-template-columns: repeat(${this.columns}, 1fr);
|
|
52
|
+
"
|
|
53
|
+
>
|
|
56
54
|
<slot></slot>
|
|
57
55
|
</div>
|
|
58
56
|
`;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# rel-menu
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
A rich menu component supporting three modes: default (selectable items), checkbox (multi-select), and arrow (nested submenus). Features keyboard navigation, focus management, disabled items, active states, and automatic submenu positioning.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
```html
|
|
8
|
+
<!-- Default menu (single selection) -->
|
|
9
|
+
<rel-menu id="defaultMenu" type="default"></rel-menu>
|
|
10
|
+
<script>
|
|
11
|
+
const menu = document.getElementById('defaultMenu');
|
|
12
|
+
menu.items = [
|
|
13
|
+
{ label: 'Edit', active: false },
|
|
14
|
+
{ label: 'Copy', active: true },
|
|
15
|
+
{ label: 'Paste', active: false },
|
|
16
|
+
{ label: 'Delete', disabled: true }
|
|
17
|
+
];
|
|
18
|
+
menu.addEventListener('item-selected', (e) => {
|
|
19
|
+
console.log('Selected:', e.detail.item.label);
|
|
20
|
+
});
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<!-- Checkbox menu (multi-select) -->
|
|
24
|
+
<rel-menu id="checkMenu" type="checkbox"></rel-menu>
|
|
25
|
+
<script>
|
|
26
|
+
const checkMenu = document.getElementById('checkMenu');
|
|
27
|
+
checkMenu.items = [
|
|
28
|
+
{ label: 'Show Grid', checked: true },
|
|
29
|
+
{ label: 'Show Rulers', checked: false },
|
|
30
|
+
{ label: 'Show Guides', checked: true }
|
|
31
|
+
];
|
|
32
|
+
checkMenu.addEventListener('item-checked', (e) => {
|
|
33
|
+
console.log(e.detail.item.label, 'is', e.detail.checked ? 'checked' : 'unchecked');
|
|
34
|
+
});
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<!-- Arrow menu (nested submenus) -->
|
|
38
|
+
<rel-menu id="arrowMenu" type="arrow"></rel-menu>
|
|
39
|
+
<script>
|
|
40
|
+
const arrowMenu = document.getElementById('arrowMenu');
|
|
41
|
+
arrowMenu.items = [
|
|
42
|
+
{ label: 'File', submenu: [
|
|
43
|
+
{ label: 'New' },
|
|
44
|
+
{ label: 'Open' },
|
|
45
|
+
{ label: 'Save', disabled: false }
|
|
46
|
+
]},
|
|
47
|
+
{ label: 'Edit', submenu: [
|
|
48
|
+
{ label: 'Undo' },
|
|
49
|
+
{ label: 'Redo' }
|
|
50
|
+
]},
|
|
51
|
+
{ label: 'Help' }
|
|
52
|
+
];
|
|
53
|
+
arrowMenu.addEventListener('submenu-selected', (e) => {
|
|
54
|
+
console.log('Submenu item:', e.detail.sub.label, 'from', e.detail.parent.label);
|
|
55
|
+
});
|
|
56
|
+
</script>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
### Attributes/Properties
|
|
62
|
+
| Name | Type | Default | Description |
|
|
63
|
+
|------|------|---------|-------------|
|
|
64
|
+
| `type` | `"default" \| "checkbox" \| "arrow"` | `"default"` | Menu behavior mode |
|
|
65
|
+
| `items` | `MenuItem[]` | `[]` | Array of menu items (see MenuItem interface below) |
|
|
66
|
+
|
|
67
|
+
### MenuItem Interface
|
|
68
|
+
```typescript
|
|
69
|
+
interface MenuItem {
|
|
70
|
+
label: string; // Display text
|
|
71
|
+
active?: boolean; // Highlighted/selected state (default/arrow modes)
|
|
72
|
+
checked?: boolean; // Checkbox state (checkbox mode)
|
|
73
|
+
disabled?: boolean; // Disables interaction
|
|
74
|
+
submenu?: MenuItem[]; // Nested menu items (arrow mode)
|
|
75
|
+
open?: boolean; // Submenu visibility state (arrow mode)
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Events
|
|
80
|
+
| Event | Detail | Description |
|
|
81
|
+
|-------|--------|-------------|
|
|
82
|
+
| `item-selected` | `{ item: MenuItem }` | Fired when an item is selected (default mode) |
|
|
83
|
+
| `item-checked` | `{ item: MenuItem, checked: boolean }` | Fired when a checkbox item is toggled (checkbox mode) |
|
|
84
|
+
| `submenu-selected` | `{ parent: MenuItem, sub: MenuItem }` | Fired when a submenu item is selected (arrow mode) |
|
|
85
|
+
|
|
86
|
+
## Slots
|
|
87
|
+
Default slot not used.
|
|
88
|
+
|
|
89
|
+
## CSS Parts
|
|
90
|
+
None exposed.
|
|
91
|
+
|
|
92
|
+
## Tokens / CSS Variables
|
|
93
|
+
|
|
94
|
+
### Semantic Tokens
|
|
95
|
+
- `--rel-fontFamilies-primary` - Font family
|
|
96
|
+
- `--rel-fontSizes-sm` - Font size
|
|
97
|
+
- `--rel-fontSizes-lg` - Chevron font size
|
|
98
|
+
- `--rel-fontWeights-medium` - Active item font weight
|
|
99
|
+
- `--rel-lineHeights-sm` - Line height
|
|
100
|
+
|
|
101
|
+
### Spacing Tokens
|
|
102
|
+
- `--rel-spacing-space-3xs` - Menu vertical padding
|
|
103
|
+
- `--rel-spacing-space-xs` - Item padding, gaps
|
|
104
|
+
- `--rel-spacing-space-sm` - Item horizontal padding
|
|
105
|
+
- `--rel-spacing-space-2xs` - Checkbox gap, submenu offset
|
|
106
|
+
|
|
107
|
+
### Color Tokens
|
|
108
|
+
- `--rel-colors-white` - Menu and submenu background
|
|
109
|
+
- `--rel-text-primary` - Default text color
|
|
110
|
+
- `--rel-text-disabled` - Disabled item text
|
|
111
|
+
- `--rel-surface-secondary` - Hover and active background
|
|
112
|
+
- `--rel-colors-gray-divider` - Active press background
|
|
113
|
+
- `--rel-colors-blue-primary` - Focus outline
|
|
114
|
+
|
|
115
|
+
### Shadow Tokens
|
|
116
|
+
- `--rel-shadows-shadow-300` - Menu and submenu drop shadow
|
|
117
|
+
|
|
118
|
+
### Border Tokens
|
|
119
|
+
- `--rel-borders-radius-border-radius-300` - Border radius
|
|
120
|
+
|
|
121
|
+
## Accessibility
|
|
122
|
+
- Uses `role="menu"` on container and `role="menuitem"` on items
|
|
123
|
+
- Keyboard navigation with Arrow keys, Enter, Space, and Escape
|
|
124
|
+
- Focus visible states with blue outline on menu and items
|
|
125
|
+
- Disabled items have reduced color and are non-interactive
|
|
126
|
+
- Close submenu when clicking outside the menu
|
|
127
|
+
|
|
128
|
+
### Keyboard Interactions
|
|
129
|
+
- `Arrow Down` - Move focus to next item
|
|
130
|
+
- `Arrow Up` - Move focus to previous item
|
|
131
|
+
- `Arrow Right` - Open focused submenu (arrow mode)
|
|
132
|
+
- `Arrow Left / Escape` - Close all submenus
|
|
133
|
+
- `Enter / Space` - Activate focused item
|
|
134
|
+
- `Tab` - Focus menu container
|
|
135
|
+
|
|
136
|
+
### Focus Behavior
|
|
137
|
+
- Menu container receives focus on Tab
|
|
138
|
+
- Focused items show blue outline with -2px offset (inside boundary)
|
|
139
|
+
- Focus index tracked programmatically for keyboard navigation
|
|
140
|
+
|
|
141
|
+
## Notes / Edge Cases
|
|
142
|
+
- **Default mode**: Clicking an item sets `active: true` on that item and `active: false` on all others
|
|
143
|
+
- **Checkbox mode**: Clicking toggles the `checked` state; also clicking the checkbox input itself triggers the same event
|
|
144
|
+
- **Arrow mode**: Submenus open on hover (`mouseenter`) and clicking toggles them; clicking a submenu item closes the submenu
|
|
145
|
+
- Submenus are positioned absolutely at `left: 100%` and `top: -<padding>` relative to parent item
|
|
146
|
+
- Clicking outside the menu (document-level listener) closes all open submenus
|
|
147
|
+
- Disabled items cannot be activated, checked, or expanded
|
|
148
|
+
- In arrow mode, only one submenu can be open at a time (opening one closes others)
|
|
149
|
+
- The menu has a minimum width of `220px`, submenus have `200px`
|
|
150
|
+
- Chevron (▸) appears only on items with `submenu` in arrow mode
|
|
151
|
+
- Native checkbox inputs are used in checkbox mode (16px × 16px)
|
|
@@ -28,16 +28,22 @@ export class RelMenu extends LitElement {
|
|
|
28
28
|
.rel-menu {
|
|
29
29
|
position: relative;
|
|
30
30
|
display: inline-block;
|
|
31
|
-
background: var(--rel-colors-white);
|
|
31
|
+
background: var(--rel-colors-white, #fff);
|
|
32
|
+
color: var(--rel-text-primary, #333);
|
|
32
33
|
border-radius: var(--rel-borders-radius-border-radius-300);
|
|
33
34
|
box-shadow: var(--rel-shadows-shadow-300);
|
|
34
35
|
min-width: 220px;
|
|
35
|
-
font-family: var(--rel-fontFamilies-primary);
|
|
36
|
+
font-family: var(--rel-fontFamilies-primary, sans-serif);
|
|
36
37
|
font-size: var(--rel-fontSizes-sm);
|
|
37
38
|
padding: var(--rel-spacing-space-3xs) 0;
|
|
38
39
|
outline: none;
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
.rel-menu:focus-visible {
|
|
43
|
+
outline: 2px solid var(--rel-colors-blue-primary, #0091ea);
|
|
44
|
+
outline-offset: 2px;
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
.rel-menu-item {
|
|
42
48
|
position: relative;
|
|
43
49
|
display: flex;
|
|
@@ -51,26 +57,27 @@ export class RelMenu extends LitElement {
|
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
.rel-menu-item:hover {
|
|
54
|
-
background: var(--rel-
|
|
60
|
+
background: var(--rel-surface-secondary, #fafafa);
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
.rel-menu-item:active {
|
|
58
|
-
background: var(--rel-colors-gray-
|
|
64
|
+
background: var(--rel-colors-gray-divider, #bdbdbd);
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
.rel-menu-item.active {
|
|
62
|
-
background: var(--rel-
|
|
68
|
+
background: var(--rel-surface-secondary, #fafafa);
|
|
69
|
+
font-weight: var(--rel-fontWeights-medium);
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
.rel-menu-item.disabled {
|
|
66
|
-
background-color:
|
|
67
|
-
color: var(--rel-
|
|
73
|
+
background-color: transparent;
|
|
74
|
+
color: var(--rel-text-disabled, #9e9e9e);
|
|
68
75
|
cursor: not-allowed;
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
.rel-menu-item[data-focused="true"] {
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
outline: 2px solid var(--rel-colors-blue-primary, #0091ea);
|
|
80
|
+
outline-offset: -2px;
|
|
74
81
|
}
|
|
75
82
|
|
|
76
83
|
.menu-check-row {
|
|
@@ -105,7 +112,8 @@ export class RelMenu extends LitElement {
|
|
|
105
112
|
top: calc(-1 * var(--rel-spacing-space-3xs));
|
|
106
113
|
left: calc(100% + var(--rel-spacing-space-2xs));
|
|
107
114
|
min-width: 200px;
|
|
108
|
-
background: var(--rel-colors-white);
|
|
115
|
+
background: var(--rel-colors-white, #fff);
|
|
116
|
+
color: var(--rel-text-primary, #333);
|
|
109
117
|
border-radius: var(--rel-borders-radius-border-radius-300);
|
|
110
118
|
box-shadow: var(--rel-shadows-shadow-300);
|
|
111
119
|
padding: var(--rel-spacing-space-3xs) 0;
|