@r2digisolutions/components 0.1.5 → 0.1.7

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 (72) hide show
  1. package/README.md +6 -1
  2. package/dist/components/atoms/Checkbox/Checkbox.svelte +10 -3
  3. package/dist/components/atoms/Checkbox/Checkbox.svelte.d.ts +3 -0
  4. package/dist/components/atoms/Input/Input.svelte +17 -2
  5. package/dist/components/atoms/Input/Input.svelte.d.ts +6 -1
  6. package/dist/components/atoms/MarqueeRect/MarqueeRect.svelte +21 -0
  7. package/dist/components/atoms/MarqueeRect/MarqueeRect.svelte.d.ts +8 -0
  8. package/dist/components/atoms/Textarea/Textarea.svelte +4 -1
  9. package/dist/components/atoms/Textarea/Textarea.svelte.d.ts +1 -0
  10. package/dist/components/atoms/Toggle/Toggle.svelte +1 -1
  11. package/dist/components/molecules/BulkActionBar/BulkActionBar.svelte +19 -5
  12. package/dist/components/molecules/CodeEditor/CodeEditor.svelte +13 -10
  13. package/dist/components/molecules/ColorPicker/ColorPicker.svelte +166 -96
  14. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.stories.d.ts +9 -0
  15. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.stories.js +8 -0
  16. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.svelte +412 -0
  17. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.svelte.d.ts +14 -0
  18. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanelStory.svelte +27 -0
  19. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanelStory.svelte.d.ts +3 -0
  20. package/dist/components/molecules/ContextMenu/ContextMenu.svelte +73 -21
  21. package/dist/components/molecules/ContextMenu/ContextMenu.svelte.d.ts +8 -1
  22. package/dist/components/molecules/DateTimePicker/DateTimePicker.svelte.d.ts +1 -1
  23. package/dist/components/molecules/FormDateTimePicker/FormDateTimePicker.svelte.d.ts +1 -1
  24. package/dist/components/molecules/Gauge/Gauge.stories.d.ts +1 -1
  25. package/dist/components/molecules/InfiniteScroll/InfiniteScroll.stories.d.ts +1 -1
  26. package/dist/components/organisms/AssetPickerPage/AssetPickerPage.svelte.d.ts +1 -1
  27. package/dist/components/organisms/BacklogPage/BacklogPage.svelte.d.ts +1 -1
  28. package/dist/components/organisms/CalendarApp/CalendarApp.svelte.d.ts +1 -1
  29. package/dist/components/organisms/DataGrid/DataGrid.stories.d.ts +65 -0
  30. package/dist/components/organisms/DataGrid/DataGrid.stories.js +95 -0
  31. package/dist/components/organisms/DataGrid/DataGrid.svelte +2264 -0
  32. package/dist/components/organisms/DataGrid/DataGrid.svelte.d.ts +99 -0
  33. package/dist/components/organisms/DataGrid/DataGridStory.svelte +659 -0
  34. package/dist/components/organisms/DataGrid/DataGridStory.svelte.d.ts +11 -0
  35. package/dist/components/organisms/DataGrid/breakpoints.d.ts +10 -0
  36. package/dist/components/organisms/DataGrid/breakpoints.js +20 -0
  37. package/dist/components/organisms/DataGrid/cellEditors.d.ts +8 -0
  38. package/dist/components/organisms/DataGrid/cellEditors.js +59 -0
  39. package/dist/components/organisms/DataGrid/conditionalFormat.d.ts +11 -0
  40. package/dist/components/organisms/DataGrid/conditionalFormat.js +98 -0
  41. package/dist/components/organisms/DataGrid/filterRows.d.ts +5 -0
  42. package/dist/components/organisms/DataGrid/filterRows.js +60 -0
  43. package/dist/components/organisms/DataGrid/marks.d.ts +9 -0
  44. package/dist/components/organisms/DataGrid/marks.js +91 -0
  45. package/dist/components/organisms/DataGrid/types.d.ts +126 -0
  46. package/dist/components/organisms/DataGrid/types.js +21 -0
  47. package/dist/components/organisms/ResourceStudio/ResourceStudio.stories.d.ts +33 -0
  48. package/dist/components/organisms/ResourceStudio/ResourceStudio.stories.js +56 -0
  49. package/dist/components/organisms/ResourceStudio/ResourceStudio.svelte +830 -0
  50. package/dist/components/organisms/ResourceStudio/ResourceStudio.svelte.d.ts +68 -0
  51. package/dist/components/organisms/ResourceStudio/ResourceStudioStory.svelte +600 -0
  52. package/dist/components/organisms/ResourceStudio/ResourceStudioStory.svelte.d.ts +7 -0
  53. package/dist/components/organisms/ResourceStudio/fieldsToColumns.d.ts +4 -0
  54. package/dist/components/organisms/ResourceStudio/fieldsToColumns.js +20 -0
  55. package/dist/components/organisms/ResourceStudio/fieldsToSchema.d.ts +6 -0
  56. package/dist/components/organisms/ResourceStudio/fieldsToSchema.js +53 -0
  57. package/dist/components/organisms/ResourceStudio/types.d.ts +69 -0
  58. package/dist/components/organisms/ResourceStudio/types.js +15 -0
  59. package/dist/components/organisms/Scheduler/Scheduler.svelte.d.ts +1 -1
  60. package/dist/components/organisms/SchemaForm/SchemaForm.svelte +10 -3
  61. package/dist/components/organisms/SchemaForm/SchemaForm.svelte.d.ts +1 -0
  62. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.stories.d.ts +25 -0
  63. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.stories.js +18 -0
  64. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.svelte +192 -0
  65. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.svelte.d.ts +62 -0
  66. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplateStory.svelte +129 -0
  67. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplateStory.svelte.d.ts +7 -0
  68. package/dist/index.d.ts +11 -0
  69. package/dist/index.js +8 -0
  70. package/dist/utils/marqueeSelect.d.ts +48 -0
  71. package/dist/utils/marqueeSelect.js +189 -0
  72. package/package.json +1 -1
@@ -45,6 +45,9 @@
45
45
 
46
46
  let rootEl = $state<HTMLDivElement | null>(null);
47
47
  let svEl = $state<HTMLDivElement | null>(null);
48
+ let triggerEl = $state<HTMLButtonElement | null>(null);
49
+ let panelEl = $state<HTMLDivElement | null>(null);
50
+ let panelStyle = $state('');
48
51
 
49
52
  let hue = $state(250);
50
53
  let sat = $state(0.72);
@@ -53,6 +56,8 @@
53
56
  let dragging: 'sv' | 'hue' | 'alpha' | null = null;
54
57
  let syncing = false;
55
58
 
59
+ const panelId = `color-picker-${Math.random().toString(36).slice(2, 9)}`;
60
+
56
61
  const rgba = $derived(hsvToRgb(hue, sat, val));
57
62
 
58
63
  const preview = $derived(
@@ -66,10 +71,11 @@
66
71
  const parsed = parseColor(value);
67
72
  if (!parsed) return;
68
73
  const hsv = rgbToHsv(parsed.r, parsed.g, parsed.b);
69
- hue = hsv.h;
70
- sat = hsv.s;
71
- val = hsv.v;
72
- alp = alpha ? parsed.a : 1;
74
+ if (hue !== hsv.h) hue = hsv.h;
75
+ if (sat !== hsv.s) sat = hsv.s;
76
+ if (val !== hsv.v) val = hsv.v;
77
+ const nextAlp = alpha ? parsed.a : 1;
78
+ if (alp !== nextAlp) alp = nextAlp;
73
79
  });
74
80
 
75
81
  function commit() {
@@ -96,15 +102,11 @@
96
102
  commit();
97
103
  }
98
104
 
99
- function onDocPointerDown(e: PointerEvent) {
100
- if (!open || !rootEl) return;
101
- const path = typeof e.composedPath === 'function' ? e.composedPath() : [];
102
- if (path.includes(rootEl) || rootEl.contains(e.target as Node)) return;
103
- open = false;
104
- }
105
-
106
105
  function onKey(e: KeyboardEvent) {
107
- if (e.key === 'Escape' && open) open = false;
106
+ if (e.key === 'Escape' && open) {
107
+ open = false;
108
+ hidePanel();
109
+ }
108
110
  }
109
111
 
110
112
  function onPointer(e: PointerEvent) {
@@ -162,15 +164,64 @@
162
164
  Math.abs(pa.a - pb.a) < 0.01
163
165
  );
164
166
  }
167
+
168
+ function positionPanel() {
169
+ if (!triggerEl) return;
170
+ const rect = triggerEl.getBoundingClientRect();
171
+ const gap = 8;
172
+ const panelW = 288;
173
+ const approxH = 340;
174
+ const spaceBelow = window.innerHeight - rect.bottom - gap;
175
+ const spaceAbove = rect.top - gap;
176
+ const openUp = spaceBelow < Math.min(approxH, 220) && spaceAbove > spaceBelow;
177
+ const left = Math.min(Math.max(8, rect.left), window.innerWidth - panelW - 8);
178
+ panelStyle = [
179
+ `top:${openUp ? 'auto' : `${rect.bottom + gap}px`}`,
180
+ `bottom:${openUp ? `${window.innerHeight - rect.top + gap}px` : 'auto'}`,
181
+ `left:${left}px`,
182
+ `width:${panelW}px`,
183
+ `margin:0`
184
+ ].join(';');
185
+ }
186
+
187
+ function showPanel() {
188
+ if (disabled || !panelEl) return;
189
+ positionPanel();
190
+ if (!panelEl.matches(':popover-open')) panelEl.showPopover();
191
+ }
192
+
193
+ function hidePanel() {
194
+ if (panelEl?.matches(':popover-open')) panelEl.hidePopover();
195
+ }
196
+
197
+ function togglePanel() {
198
+ if (disabled) return;
199
+ if (panelEl?.matches(':popover-open')) hidePanel();
200
+ else showPanel();
201
+ }
202
+
203
+ function handleBeforeToggle(event: ToggleEvent) {
204
+ if (event.newState === 'open') {
205
+ if (disabled) {
206
+ event.preventDefault();
207
+ return;
208
+ }
209
+ positionPanel();
210
+ }
211
+ }
212
+
213
+ function handleToggle(event: ToggleEvent) {
214
+ open = event.newState === 'open';
215
+ }
165
216
  </script>
166
217
 
167
- <svelte:document
168
- onpointerdown={onDocPointerDown}
169
- onkeydown={onKey}
170
- onpointermove={onPointer}
171
- onpointerup={onPointerUp}
218
+ <svelte:window
219
+ onscroll={() => open && positionPanel()}
220
+ onresize={() => open && positionPanel()}
172
221
  />
173
222
 
223
+ <svelte:document onkeydown={onKey} onpointermove={onPointer} onpointerup={onPointerUp} />
224
+
174
225
  <div class={['relative w-full max-w-xs', className]} bind:this={rootEl}>
175
226
  {#if label}
176
227
  <span class="mb-1.5 block text-sm font-medium text-primary">{label}</span>
@@ -178,9 +229,12 @@
178
229
 
179
230
  <button
180
231
  type="button"
232
+ bind:this={triggerEl}
181
233
  {disabled}
182
234
  aria-expanded={open}
183
- onclick={() => !disabled && (open = !open)}
235
+ aria-controls={panelId}
236
+ aria-haspopup="dialog"
237
+ onclick={togglePanel}
184
238
  class={[
185
239
  'flex h-10 w-full items-center gap-2.5 rounded-xl border border-border bg-surface-elevated px-2.5 text-left transition-colors',
186
240
  'hover:bg-surface-overlay focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500/20',
@@ -197,99 +251,115 @@
197
251
  </svg>
198
252
  </button>
199
253
 
200
- {#if open}
254
+ <div
255
+ bind:this={panelEl}
256
+ id={panelId}
257
+ popover="auto"
258
+ role="dialog"
259
+ aria-label="Color picker"
260
+ class="color-picker-panel z-50 rounded-2xl border border-border bg-surface-elevated p-3 shadow-xl"
261
+ style={panelStyle}
262
+ onbeforetoggle={handleBeforeToggle}
263
+ ontoggle={handleToggle}
264
+ >
201
265
  <div
202
- role="dialog"
203
- aria-label="Color picker"
204
- class="absolute left-0 z-50 mt-2 w-72 rounded-2xl border border-border bg-surface-elevated p-3 shadow-xl"
266
+ bind:this={svEl}
267
+ role="presentation"
268
+ class="relative h-36 w-full cursor-crosshair touch-none overflow-hidden rounded-xl"
269
+ style:background={`linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(${hue} 100% 50%))`}
270
+ onpointerdown={startSv}
205
271
  >
206
- <!-- Saturation / Value -->
207
- <div
208
- bind:this={svEl}
209
- role="presentation"
210
- class="relative h-36 w-full cursor-crosshair touch-none overflow-hidden rounded-xl"
211
- style:background={`linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(${hue} 100% 50%))`}
212
- onpointerdown={startSv}
213
- >
214
- <span
215
- class="pointer-events-none absolute h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow"
216
- style:left={`${sat * 100}%`}
217
- style:top={`${(1 - val) * 100}%`}
218
- style:background={preview}
219
- ></span>
220
- </div>
272
+ <span
273
+ class="pointer-events-none absolute h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow"
274
+ style:left={`${sat * 100}%`}
275
+ style:top={`${(1 - val) * 100}%`}
276
+ style:background={preview}
277
+ ></span>
278
+ </div>
221
279
 
222
- <!-- Hue -->
223
- <label class="mt-3 block">
224
- <span class="sr-only">Hue</span>
280
+ <label class="mt-3 block">
281
+ <span class="sr-only">Hue</span>
282
+ <input
283
+ type="range"
284
+ min="0"
285
+ max="360"
286
+ step="1"
287
+ value={hue}
288
+ oninput={onHueInput}
289
+ class="cp-hue h-3 w-full cursor-pointer appearance-none rounded-full"
290
+ />
291
+ </label>
292
+
293
+ {#if alpha}
294
+ <label class="mt-2 block">
295
+ <span class="sr-only">Opacity</span>
225
296
  <input
226
297
  type="range"
227
298
  min="0"
228
- max="360"
229
- step="1"
230
- value={hue}
231
- oninput={onHueInput}
232
- class="cp-hue h-3 w-full cursor-pointer appearance-none rounded-full"
299
+ max="1"
300
+ step="0.01"
301
+ value={alp}
302
+ oninput={onAlphaInput}
303
+ class="cp-alpha h-3 w-full cursor-pointer appearance-none rounded-full"
304
+ style:--cp-alpha-color={`rgba(${rgba.r},${rgba.g},${rgba.b},1)`}
233
305
  />
234
306
  </label>
235
-
307
+ {/if}
308
+
309
+ <div class="mt-3 flex items-center gap-2">
310
+ <span class="cp-checker relative h-9 w-9 shrink-0 overflow-hidden rounded-lg border border-border">
311
+ <span class="absolute inset-0" style:background={preview}></span>
312
+ </span>
313
+ <input
314
+ type="text"
315
+ value={formatted}
316
+ onchange={onHexInput}
317
+ onkeydown={(e) => e.key === 'Enter' && onHexInput(e)}
318
+ class="h-9 min-w-0 flex-1 rounded-lg border border-border bg-surface px-2.5 font-mono text-xs text-primary outline-none focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20"
319
+ aria-label="Color value"
320
+ />
236
321
  {#if alpha}
237
- <label class="mt-2 block">
238
- <span class="sr-only">Opacity</span>
239
- <input
240
- type="range"
241
- min="0"
242
- max="1"
243
- step="0.01"
244
- value={alp}
245
- oninput={onAlphaInput}
246
- class="cp-alpha h-3 w-full cursor-pointer appearance-none rounded-full"
247
- style:--cp-alpha-color={`rgb(${rgba.r},${rgba.g},${rgba.b},1)`}
248
- />
249
- </label>
250
- {/if}
251
-
252
- <div class="mt-3 flex items-center gap-2">
253
- <span class="cp-checker relative h-9 w-9 shrink-0 overflow-hidden rounded-lg border border-border">
254
- <span class="absolute inset-0" style:background={preview}></span>
322
+ <span class="w-10 shrink-0 text-right font-mono text-[11px] text-muted">
323
+ {Math.round(alp * 100)}%
255
324
  </span>
256
- <input
257
- type="text"
258
- value={formatted}
259
- onchange={onHexInput}
260
- onkeydown={(e) => e.key === 'Enter' && onHexInput(e)}
261
- class="h-9 min-w-0 flex-1 rounded-lg border border-border bg-surface px-2.5 font-mono text-xs text-primary outline-none focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20"
262
- aria-label="Color value"
263
- />
264
- {#if alpha}
265
- <span class="w-10 shrink-0 text-right font-mono text-[11px] text-muted">
266
- {Math.round(alp * 100)}%
267
- </span>
268
- {/if}
269
- </div>
270
-
271
- {#if showSwatches}
272
- <div class="mt-3 flex flex-wrap gap-1.5">
273
- {#each swatches as swatch (swatch)}
274
- <button
275
- type="button"
276
- onclick={() => pickSwatch(swatch)}
277
- class={[
278
- 'cp-checker relative h-7 w-7 overflow-hidden rounded-full border border-border transition-transform hover:scale-110',
279
- sameColor(value, swatch) && 'ring-2 ring-brand-500 ring-offset-2 ring-offset-surface-elevated'
280
- ]}
281
- aria-label={`Select ${swatch}`}
282
- >
283
- <span class="absolute inset-0" style:background={swatch}></span>
284
- </button>
285
- {/each}
286
- </div>
287
325
  {/if}
288
326
  </div>
289
- {/if}
327
+
328
+ {#if showSwatches}
329
+ <div class="mt-3 flex flex-wrap gap-1.5">
330
+ {#each swatches as swatch (swatch)}
331
+ <button
332
+ type="button"
333
+ onclick={() => pickSwatch(swatch)}
334
+ class={[
335
+ 'cp-checker relative h-7 w-7 overflow-hidden rounded-full border border-border transition-transform hover:scale-110',
336
+ sameColor(value, swatch) &&
337
+ 'ring-2 ring-brand-500 ring-offset-2 ring-offset-surface-elevated'
338
+ ]}
339
+ aria-label={`Select ${swatch}`}
340
+ >
341
+ <span class="absolute inset-0" style:background={swatch}></span>
342
+ </button>
343
+ {/each}
344
+ </div>
345
+ {/if}
346
+ </div>
290
347
  </div>
291
348
 
292
349
  <style>
350
+
351
+ .color-picker-panel {
352
+ position: fixed;
353
+ }
354
+
355
+ .color-picker-panel:popover-open {
356
+ display: block;
357
+ }
358
+
359
+ .color-picker-panel:not(:popover-open) {
360
+ display: none;
361
+ }
362
+
293
363
  .cp-checker {
294
364
  background-color: #fff;
295
365
  background-image:
@@ -0,0 +1,9 @@
1
+ import type { StoryObj } from '@storybook/svelte';
2
+ declare const meta: {
3
+ title: string;
4
+ component: import("svelte").Component<Record<string, never>, {}, "">;
5
+ tags: string[];
6
+ };
7
+ export default meta;
8
+ type Story = StoryObj<typeof meta>;
9
+ export declare const Default: Story;
@@ -0,0 +1,8 @@
1
+ import ConditionalFormatPanelStory from './ConditionalFormatPanelStory.svelte';
2
+ const meta = {
3
+ title: 'Molecules/ConditionalFormatPanel',
4
+ component: ConditionalFormatPanelStory,
5
+ tags: ['autodocs']
6
+ };
7
+ export default meta;
8
+ export const Default = {};