@reliability-design/web 1.0.2

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 (60) hide show
  1. package/dist/components/rel-accordion/rel-accordion.stories.ts +313 -0
  2. package/dist/components/rel-accordion/rel-accordion.ts +114 -0
  3. package/dist/components/rel-alert/rel-alert.stories.ts +412 -0
  4. package/dist/components/rel-alert/rel-alert.ts +194 -0
  5. package/dist/components/rel-avatar/rel-avatar.stories.ts +327 -0
  6. package/dist/components/rel-avatar/rel-avatar.ts +100 -0
  7. package/dist/components/rel-badge/rel-badge.stories.ts +350 -0
  8. package/dist/components/rel-badge/rel-badge.ts +70 -0
  9. package/dist/components/rel-breadcrumb/rel-breadcrumb.stories.ts +306 -0
  10. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +97 -0
  11. package/dist/components/rel-button/rel-button.stories.ts +356 -0
  12. package/dist/components/rel-button/rel-button.ts +204 -0
  13. package/dist/components/rel-card/rel-card.stories.ts +299 -0
  14. package/dist/components/rel-card/rel-card.ts +33 -0
  15. package/dist/components/rel-cardmedia/rel-cardmedia.stories.ts +368 -0
  16. package/dist/components/rel-cardmedia/rel-cardmedia.ts +80 -0
  17. package/dist/components/rel-checkbox/rel-checkbox.stories.ts +414 -0
  18. package/dist/components/rel-checkbox/rel-checkbox.ts +164 -0
  19. package/dist/components/rel-chip/rel-chip.stories.ts +552 -0
  20. package/dist/components/rel-chip/rel-chip.ts +261 -0
  21. package/dist/components/rel-container/rel-container.stories.ts +239 -0
  22. package/dist/components/rel-container/rel-container.ts +74 -0
  23. package/dist/components/rel-divider/rel-divider.stories.ts +229 -0
  24. package/dist/components/rel-divider/rel-divider.ts +44 -0
  25. package/dist/components/rel-layout/rel-layout.stories.ts +713 -0
  26. package/dist/components/rel-layout/rel-layout.ts +60 -0
  27. package/dist/components/rel-menu/rel-menu.stories.ts +910 -0
  28. package/dist/components/rel-menu/rel-menu.ts +319 -0
  29. package/dist/components/rel-progress/rel-progress.stories.ts +817 -0
  30. package/dist/components/rel-progress/rel-progress.ts +182 -0
  31. package/dist/components/rel-radio/rel-radio.stories.ts +1048 -0
  32. package/dist/components/rel-radio/rel-radio.ts +187 -0
  33. package/dist/components/rel-segmented-button/rel-segmented-button.stories.ts +1079 -0
  34. package/dist/components/rel-segmented-button/rel-segmented-button.ts +150 -0
  35. package/dist/components/rel-select/rel-select.stories.ts +1201 -0
  36. package/dist/components/rel-select/rel-select.ts +261 -0
  37. package/dist/components/rel-slider/rel-slider.stories.ts +730 -0
  38. package/dist/components/rel-slider/rel-slider.ts +440 -0
  39. package/dist/components/rel-snackbar/rel-snackbar.stories.ts +808 -0
  40. package/dist/components/rel-snackbar/rel-snackbar.ts +212 -0
  41. package/dist/components/rel-stepper/rel-stepper.stories.ts +752 -0
  42. package/dist/components/rel-stepper/rel-stepper.ts +425 -0
  43. package/dist/components/rel-switch/rel-switch.stories.ts +441 -0
  44. package/dist/components/rel-switch/rel-switch.ts +161 -0
  45. package/dist/components/rel-tab/rel-tab.stories.ts +492 -0
  46. package/dist/components/rel-tab/rel-tab.ts +145 -0
  47. package/dist/components/rel-textfield/rel-textfield.stories.ts +710 -0
  48. package/dist/components/rel-textfield/rel-textfield.ts +224 -0
  49. package/dist/components/rel-toast/rel-toast.stories.ts +394 -0
  50. package/dist/components/rel-toast/rel-toast.ts +154 -0
  51. package/dist/components/rel-tooltip/rel-tooltip.stories.ts +364 -0
  52. package/dist/components/rel-tooltip/rel-tooltip.ts +80 -0
  53. package/dist/index.d.mts +372 -0
  54. package/dist/index.d.ts +372 -0
  55. package/dist/index.js +4593 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/index.mjs +4544 -0
  58. package/dist/index.mjs.map +1 -0
  59. package/dist/styles/vars.css +184 -0
  60. package/package.json +32 -0
@@ -0,0 +1,440 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property, state } from "lit/decorators.js";
3
+
4
+ export type SliderType = "continuous" | "discrete";
5
+ export type TrackStyle = "solid" | "dotted";
6
+
7
+ @customElement("rel-slider")
8
+ export class RelSlider extends LitElement {
9
+ @property({ type: String }) type: SliderType = "continuous";
10
+
11
+ @property({ type: Number }) min: number = 0;
12
+
13
+ @property({ type: Number }) max: number = 100;
14
+
15
+ @property({ type: Number }) step: number = 1;
16
+
17
+ @property({ type: Boolean }) disabled: boolean = false;
18
+
19
+ @property({ type: String }) track: TrackStyle = "solid";
20
+
21
+ @property({ type: Boolean }) showTickLabels: boolean = false;
22
+
23
+ @property({ type: Boolean }) showBubble: boolean = true;
24
+
25
+ @property({ type: Number }) value: number = 0;
26
+
27
+ @state() private ticks: number[] = [];
28
+
29
+ static styles = css`
30
+ :host {
31
+ --track-height: 5px;
32
+ --thumb-size: 10px;
33
+ --thumb-stroke: 7px;
34
+ --thumb-halo-color: rgba(224, 222, 222, 0.8);
35
+ --tick-size: 4px;
36
+ --shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
37
+ --halo: 0 2px 0 #e9e9e9, 0 6px 10px rgba(0, 0, 0, 0.07);
38
+ --marker-width: 24px;
39
+ --marker-height: 28px;
40
+
41
+ display: block;
42
+ font-family: var(--rel-fontFamilies-primary);
43
+ }
44
+
45
+ .rel-slider {
46
+ position: relative;
47
+ width: 100%;
48
+ height: 60px;
49
+ user-select: none;
50
+ }
51
+
52
+ /* Track */
53
+ .track {
54
+ position: absolute;
55
+ top: 50%;
56
+ left: 0;
57
+ width: 100%;
58
+ height: var(--track-height);
59
+ background: var(--rel-colors-gray-border);
60
+ border-radius: 2px;
61
+ transform: translateY(-50%);
62
+ pointer-events: none;
63
+ }
64
+
65
+ .track-active {
66
+ position: absolute;
67
+ top: 50%;
68
+ left: 0;
69
+ height: var(--track-height);
70
+ background: var(--rel-colors-black);
71
+ border-radius: 2px;
72
+ transform: translateY(-50%);
73
+ pointer-events: none;
74
+ }
75
+
76
+ .track-active.dotted {
77
+ background: radial-gradient(
78
+ circle,
79
+ var(--rel-colors-white) 0 1px,
80
+ transparent 1px
81
+ )
82
+ center/12px 4px repeat-x,
83
+ var(--rel-colors-black);
84
+ }
85
+
86
+ /* Input */
87
+ .slider-input {
88
+ -webkit-appearance: none;
89
+ appearance: none;
90
+ position: absolute;
91
+ top: 0;
92
+ width: 100%;
93
+ left: 0;
94
+ height: 100%;
95
+ background: transparent;
96
+ outline: none;
97
+ cursor: pointer;
98
+ z-index: 2;
99
+ margin: 0;
100
+ padding: 0;
101
+ }
102
+
103
+ .slider-input::-webkit-slider-runnable-track {
104
+ background: transparent;
105
+ height: 100%;
106
+ border: none;
107
+ }
108
+
109
+ .slider-input::-moz-range-track {
110
+ background: transparent;
111
+ height: 100%;
112
+ border: none;
113
+ }
114
+
115
+ /* Hide native thumb */
116
+ .slider-input::-webkit-slider-thumb {
117
+ -webkit-appearance: none;
118
+ appearance: none;
119
+ width: 1px;
120
+ height: 1px;
121
+ background: transparent;
122
+ border: none;
123
+ cursor: pointer;
124
+ }
125
+
126
+ .slider-input::-moz-range-thumb {
127
+ width: 1px;
128
+ height: 1px;
129
+ background: transparent;
130
+ border: none;
131
+ cursor: pointer;
132
+ }
133
+
134
+ /* Custom Thumb Container */
135
+ .thumb-container {
136
+ position: absolute;
137
+ left: 0;
138
+ top: 23.5%;
139
+ transform: translate(-50%, -50%);
140
+ pointer-events: none;
141
+ z-index: 5;
142
+ display: flex;
143
+ flex-direction: column;
144
+ align-items: center;
145
+ gap: 0;
146
+ }
147
+
148
+ /* Value Marker */
149
+ .value-marker {
150
+ width: var(--marker-width);
151
+ height: var(--marker-height);
152
+ margin-bottom: 4px;
153
+ }
154
+
155
+ .value-marker svg {
156
+ width: 100%;
157
+ height: 100%;
158
+ display: block;
159
+ }
160
+
161
+ /* Custom Thumb */
162
+ .custom-thumb {
163
+ width: var(--thumb-size);
164
+ height: var(--thumb-size);
165
+ background: var(--rel-colors-black);
166
+ border-radius: 50%;
167
+ transition: box-shadow 0.15s ease;
168
+ }
169
+
170
+ .slider-input:active ~ .thumb-container .custom-thumb {
171
+ box-shadow: 0 0 0 var(--thumb-stroke) var(--thumb-halo-color),
172
+ var(--shadow), var(--halo);
173
+ }
174
+
175
+ /* Ticks */
176
+ .ticks {
177
+ position: absolute;
178
+ top: 50%;
179
+ left: 0;
180
+ width: 100%;
181
+ transform: translateY(-50%);
182
+ pointer-events: none;
183
+ }
184
+
185
+ .tick {
186
+ position: absolute;
187
+ width: var(--tick-size);
188
+ height: var(--tick-size);
189
+ background: var(--rel-colors-gray-primary);
190
+ border-radius: 50%;
191
+ transform: translate(-50%, -50%);
192
+ transition: background 0.2s;
193
+ z-index: 3;
194
+ }
195
+
196
+ .tick.active {
197
+ background: var(--rel-colors-white);
198
+ }
199
+
200
+ /* Tick labels */
201
+ .tick-labels {
202
+ position: absolute;
203
+ top: calc(50% + var(--tick-size) + 6px);
204
+ left: 0;
205
+ width: 100%;
206
+ font-size: var(--rel-fontSizes-xs);
207
+ color: var(--rel-colors-gray-heading);
208
+ pointer-events: none;
209
+ }
210
+
211
+ .tick-label {
212
+ position: absolute;
213
+ transform: translateX(-50%);
214
+ }
215
+
216
+ /* Disabled State */
217
+ .rel-slider.disabled .track {
218
+ background: var(--rel-colors-gray-primary);
219
+ }
220
+
221
+ .rel-slider.disabled .track-active {
222
+ background: var(--rel-colors-gray-placeholder);
223
+ }
224
+
225
+ .rel-slider.disabled .track-active.dotted {
226
+ background: radial-gradient(
227
+ circle,
228
+ #eaeaea 0 1px,
229
+ transparent 1px
230
+ )
231
+ center/12px 4px repeat-x,
232
+ var(--rel-colors-gray-placeholder);
233
+ }
234
+
235
+ .rel-slider.disabled .tick {
236
+ background: var(--rel-colors-gray-placeholder);
237
+ }
238
+
239
+ .rel-slider.disabled .tick-label {
240
+ color: var(--rel-colors-gray-placeholder);
241
+ }
242
+
243
+ .rel-slider.disabled .slider-input {
244
+ cursor: not-allowed;
245
+ }
246
+
247
+ .rel-slider.disabled .custom-thumb {
248
+ background: var(--rel-colors-gray-placeholder);
249
+ box-shadow: 0 0 0 var(--thumb-stroke) #f5f5f5;
250
+ }
251
+
252
+ .rel-slider.disabled .value-marker svg path {
253
+ fill: var(--rel-colors-gray-placeholder);
254
+ }
255
+ `;
256
+
257
+ connectedCallback() {
258
+ super.connectedCallback();
259
+ this.setupTicks();
260
+ }
261
+
262
+ updated(changedProperties: Map<string, any>) {
263
+ if (
264
+ changedProperties.has("type") ||
265
+ changedProperties.has("min") ||
266
+ changedProperties.has("max") ||
267
+ changedProperties.has("step")
268
+ ) {
269
+ this.setupTicks();
270
+ }
271
+ if (changedProperties.has("value")) {
272
+ this.updateActiveWidth();
273
+ }
274
+ }
275
+
276
+ private get percentage(): number {
277
+ if (this.max === this.min) return 0;
278
+ return ((this.value - this.min) / (this.max - this.min)) * 100;
279
+ }
280
+
281
+ private setupTicks() {
282
+ if (this.type !== "discrete") {
283
+ this.ticks = [];
284
+ return;
285
+ }
286
+
287
+ const step = Math.max(1, this.step);
288
+ const ticks: number[] = [];
289
+ for (let v = this.min; v <= this.max; v += step) {
290
+ ticks.push(v);
291
+ }
292
+ if (ticks[ticks.length - 1] !== this.max) {
293
+ ticks.push(this.max);
294
+ }
295
+ this.ticks = ticks;
296
+ }
297
+
298
+ private getTickLeftPct(tick: number): number {
299
+ const pct = ((tick - this.min) / (this.max - this.min)) * 100;
300
+ return Math.round(pct * 1000) / 1000;
301
+ }
302
+
303
+ private isTickActive(tick: number): boolean {
304
+ return tick <= this.value;
305
+ }
306
+
307
+ private onInput(ev: Event) {
308
+ const el = ev.target as HTMLInputElement;
309
+ let next = Number(el.value);
310
+
311
+ if (this.type === "discrete") {
312
+ const snapped =
313
+ Math.round((next - this.min) / this.step) * this.step + this.min;
314
+ next = Math.min(this.max, Math.max(this.min, snapped));
315
+ el.value = String(next);
316
+ }
317
+
318
+ this.value = next;
319
+ this.updateActiveWidth();
320
+ this.dispatchEvent(
321
+ new CustomEvent("valueChange", {
322
+ detail: { value: this.value },
323
+ bubbles: true,
324
+ composed: true,
325
+ })
326
+ );
327
+ }
328
+
329
+ private updateActiveWidth() {
330
+ const activeEl = this.shadowRoot?.querySelector(".track-active") as HTMLDivElement;
331
+ if (activeEl) {
332
+ if (this.type === "discrete") {
333
+ const stepPercent = (this.step / (this.max - this.min)) * 100;
334
+ const snappedPct = Math.round(this.percentage / stepPercent) * stepPercent;
335
+ activeEl.style.width = `${snappedPct}%`;
336
+ } else {
337
+ activeEl.style.width = `${this.percentage}%`;
338
+ }
339
+ }
340
+ }
341
+
342
+ private renderThumbContainer() {
343
+ return html`
344
+ <div class="thumb-container" style="left: ${this.percentage}%">
345
+ ${this.showBubble ? html`
346
+ <div class="value-marker">
347
+ <svg viewBox="0 0 24 32" xmlns="http://www.w3.org/2000/svg">
348
+ <path
349
+ d="M12 0C18.6274 0 24 5.37258 24 12C24 21 12 32 12 32C12 32 0 21 0 12C0 5.37258 5.37258 0 12 0Z"
350
+ fill="black" />
351
+ <text
352
+ x="12"
353
+ y="16"
354
+ text-anchor="middle"
355
+ fill="white"
356
+ font-size="12"
357
+ font-family="Poppins"
358
+ font-weight="600">
359
+ ${this.value}
360
+ </text>
361
+ </svg>
362
+ </div>
363
+ ` : ""}
364
+ <div class="custom-thumb"></div>
365
+ </div>
366
+ `;
367
+ }
368
+
369
+ private renderTicks() {
370
+ if (this.type !== "discrete") return "";
371
+
372
+ return html`
373
+ <div class="ticks">
374
+ ${this.ticks.map(
375
+ (tick) => html`
376
+ <div
377
+ class="tick ${this.isTickActive(tick) ? "active" : ""}"
378
+ style="left: ${this.getTickLeftPct(tick)}%"></div>
379
+ `
380
+ )}
381
+ </div>
382
+ `;
383
+ }
384
+
385
+ private renderTickLabels() {
386
+ if (this.type !== "discrete" || !this.showTickLabels) return "";
387
+
388
+ return html`
389
+ <div class="tick-labels">
390
+ ${this.ticks.map(
391
+ (tick) => html`
392
+ <div
393
+ class="tick-label"
394
+ style="left: ${this.getTickLeftPct(tick)}%">
395
+ ${tick}
396
+ </div>
397
+ `
398
+ )}
399
+ </div>
400
+ `;
401
+ }
402
+
403
+ render() {
404
+ const sliderClasses = [
405
+ "rel-slider",
406
+ this.disabled ? "disabled" : "",
407
+ this.type === "discrete" ? "has-ticks" : "",
408
+ ]
409
+ .filter(Boolean)
410
+ .join(" ");
411
+
412
+ const trackActiveClasses = [
413
+ "track-active",
414
+ this.track === "dotted" ? "dotted" : "",
415
+ ]
416
+ .filter(Boolean)
417
+ .join(" ");
418
+
419
+ return html`
420
+ <div class="${sliderClasses}">
421
+ <div class="track"></div>
422
+ <div class="${trackActiveClasses}"></div>
423
+
424
+ <input
425
+ class="slider-input"
426
+ type="range"
427
+ .min="${String(this.min)}"
428
+ .max="${String(this.max)}"
429
+ .step="${this.type === 'discrete' ? String(this.step) : '1'}"
430
+ .value="${String(this.value)}"
431
+ ?disabled="${this.disabled}"
432
+ @input="${this.onInput}" />
433
+
434
+ ${this.renderThumbContainer()}
435
+ ${this.renderTicks()}
436
+ ${this.renderTickLabels()}
437
+ </div>
438
+ `;
439
+ }
440
+ }