@rettangoli/ui 0.1.2-rc3 → 0.1.2-rc31

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 (56) hide show
  1. package/dist/rettangoli-iife-layout.min.js +115 -43
  2. package/dist/rettangoli-iife-ui.min.js +187 -67
  3. package/package.json +5 -3
  4. package/src/cli/buildSvg.js +86 -0
  5. package/src/cli/index.js +1 -0
  6. package/src/common.js +19 -0
  7. package/src/components/breadcrumb/breadcrumb.handlers.js +9 -0
  8. package/src/components/breadcrumb/breadcrumb.store.js +29 -0
  9. package/src/components/breadcrumb/breadcrumb.view.yaml +64 -0
  10. package/src/components/dropdownMenu/dropdownMenu.handlers.js +4 -4
  11. package/src/components/dropdownMenu/dropdownMenu.store.js +5 -17
  12. package/src/components/dropdownMenu/dropdownMenu.view.yaml +15 -13
  13. package/src/components/form/form.handlers.js +173 -25
  14. package/src/components/form/form.store.js +176 -22
  15. package/src/components/form/form.view.yaml +217 -33
  16. package/src/components/pageOutline/pageOutline.handlers.js +57 -17
  17. package/src/components/pageOutline/pageOutline.store.js +46 -1
  18. package/src/components/pageOutline/pageOutline.view.yaml +7 -5
  19. package/src/components/popoverInput/popoverInput.handlers.js +99 -0
  20. package/src/components/popoverInput/popoverInput.store.js +48 -0
  21. package/src/components/popoverInput/popoverInput.view.yaml +55 -0
  22. package/src/components/select/select.handlers.js +116 -11
  23. package/src/components/select/select.store.js +84 -18
  24. package/src/components/select/select.view.yaml +40 -10
  25. package/src/components/sidebar/sidebar.view.yaml +1 -1
  26. package/src/components/sliderInput/sliderInput.handlers.js +41 -0
  27. package/src/components/sliderInput/sliderInput.store.js +18 -0
  28. package/src/components/sliderInput/sliderInput.view.yaml +42 -0
  29. package/src/components/table/table.handlers.js +1 -1
  30. package/src/components/tabs/tabs.handlers.js +10 -0
  31. package/src/components/tabs/tabs.store.js +29 -0
  32. package/src/components/tabs/tabs.view.yaml +64 -0
  33. package/src/components/tooltip/tooltip.handlers.js +0 -0
  34. package/src/components/tooltip/tooltip.store.js +12 -0
  35. package/src/components/tooltip/tooltip.view.yaml +27 -0
  36. package/src/components/waveform/waveform.handlers.js +92 -0
  37. package/src/components/waveform/waveform.store.js +17 -0
  38. package/src/components/waveform/waveform.view.yaml +38 -0
  39. package/src/entry-iife-layout.js +3 -0
  40. package/src/entry-iife-ui.js +4 -0
  41. package/src/index.js +5 -1
  42. package/src/primitives/button.js +10 -0
  43. package/src/primitives/colorPicker.js +9 -0
  44. package/src/primitives/dialog.js +254 -0
  45. package/src/primitives/input.js +41 -11
  46. package/src/primitives/popover.js +280 -0
  47. package/src/primitives/slider.js +18 -9
  48. package/src/primitives/svg.js +2 -0
  49. package/src/primitives/textarea.js +25 -1
  50. package/src/styles/cursorStyles.js +38 -2
  51. package/src/components/dialog/dialog.handlers.js +0 -5
  52. package/src/components/dialog/dialog.store.js +0 -25
  53. package/src/components/dialog/dialog.view.yaml +0 -44
  54. package/src/components/popover/popover.handlers.js +0 -5
  55. package/src/components/popover/popover.store.js +0 -12
  56. package/src/components/popover/popover.view.yaml +0 -57
@@ -0,0 +1,41 @@
1
+ export const handleBeforeMount = (deps) => {
2
+ const { store, attrs } = deps;
3
+ store.setValue(attrs.defaultValue || 0);
4
+ }
5
+
6
+ export const handleOnUpdate = (changes, deps) => {
7
+ const { oldAttrs, newAttrs } = changes;
8
+ const { store, render, attrs } = deps;
9
+
10
+ // Reset when key changes
11
+ if (oldAttrs?.key !== newAttrs?.key && newAttrs?.key) {
12
+ const defaultValue = newAttrs?.defaultValue || attrs?.defaultValue || 0;
13
+ store.setValue(defaultValue);
14
+ render();
15
+ } else if (oldAttrs?.defaultValue !== newAttrs?.defaultValue) {
16
+ // Also reset when defaultValue changes
17
+ const defaultValue = newAttrs?.defaultValue || 0;
18
+ store.setValue(defaultValue);
19
+ render();
20
+ }
21
+ }
22
+
23
+ export const handleValueChange = (e, deps) => {
24
+ const { store, render, dispatchEvent } = deps;
25
+ const newValue = Number(e.detail.value);
26
+
27
+ store.setValue(newValue);
28
+
29
+ // Re-render to sync slider and input
30
+ render();
31
+
32
+ // Dispatch event for external listeners
33
+ dispatchEvent(
34
+ new CustomEvent("slider-input-value-change", {
35
+ detail: {
36
+ value: newValue,
37
+ },
38
+ bubbles: true,
39
+ }),
40
+ );
41
+ };
@@ -0,0 +1,18 @@
1
+ export const INITIAL_STATE = Object.freeze({
2
+ value: 0
3
+ });
4
+
5
+ export const toViewData = ({ state, attrs }) => {
6
+ return {
7
+ key: attrs.key,
8
+ value: state.value,
9
+ w: attrs.w || '',
10
+ min: attrs.min || 0,
11
+ max: attrs.max || 100,
12
+ step: attrs.step || 1
13
+ };
14
+ }
15
+
16
+ export const setValue = (state, newValue) => {
17
+ state.value = newValue;
18
+ }
@@ -0,0 +1,42 @@
1
+ elementName: rtgl-slider-input
2
+
3
+ viewDataSchema:
4
+ type: object
5
+
6
+ attrsSchema:
7
+ type: object
8
+ properties:
9
+ defaultValue:
10
+ type: string
11
+ default: '0'
12
+ w:
13
+ type: string
14
+ default: ''
15
+ min:
16
+ type: string
17
+ default: '0'
18
+ max:
19
+ type: string
20
+ default: '100'
21
+ step:
22
+ type: string
23
+ default: '1'
24
+
25
+ refs:
26
+ input:
27
+ eventListeners:
28
+ input-change:
29
+ handler: handleValueChange
30
+ slider:
31
+ eventListeners:
32
+ slider-change:
33
+ handler: handleValueChange
34
+
35
+ events:
36
+ form-change: {}
37
+
38
+ template:
39
+ - rtgl-view d=h av=c g=md w=${w}:
40
+ - rtgl-slider#slider key=${key} w=f type=range min=${min} max=${max} step=${step} value=${value}:
41
+ - rtgl-view w=84:
42
+ - rtgl-input#input key=${key} w=f type=number min=${min} max=${max} step=${step} value=${value}:
@@ -1,4 +1,4 @@
1
- export const handleOnMount = (deps) => {
1
+ export const handleBeforeMount = (deps) => {
2
2
  // No special initialization needed for basic table
3
3
  };
4
4
 
@@ -0,0 +1,10 @@
1
+ export const handleClickItem = (e, deps) => {
2
+ const { dispatchEvent } = deps;
3
+ const id = e.currentTarget.dataset.id;
4
+
5
+ dispatchEvent(new CustomEvent('item-click', {
6
+ detail: {
7
+ id
8
+ }
9
+ }));
10
+ }
@@ -0,0 +1,29 @@
1
+ export const INITIAL_STATE = Object.freeze({});
2
+
3
+ const blacklistedAttrs = ['id', 'class', 'style', 'slot'];
4
+
5
+ const stringifyAttrs = (attrs) => {
6
+ return Object.entries(attrs).filter(([key]) => !blacklistedAttrs.includes(key)).map(([key, value]) => `${key}=${value}`).join(' ');
7
+ }
8
+
9
+ export const toViewData = ({ state, props, attrs }) => {
10
+ const containerAttrString = stringifyAttrs(attrs);
11
+
12
+ const items = props.items || [];
13
+ const selectedTab = attrs['selected-tab'];
14
+
15
+ // Mark selected tab with styling
16
+ const itemsWithSelection = items.map(item => ({
17
+ ...item,
18
+ isSelected: item.id === selectedTab,
19
+ bgColor: item.id === selectedTab ? 'ac' : '',
20
+ borderColor: item.id === selectedTab ? '' : 'tr',
21
+ textColor: item.id === selectedTab ? '' : 'mu-fg'
22
+ }));
23
+
24
+ return {
25
+ containerAttrString,
26
+ items: itemsWithSelection,
27
+ selectedTab
28
+ };
29
+ }
@@ -0,0 +1,64 @@
1
+ elementName: rtgl-tabs
2
+
3
+ viewDataSchema:
4
+ type: object
5
+ properties:
6
+ containerAttrString:
7
+ type: string
8
+ items:
9
+ type: array
10
+ items:
11
+ type: object
12
+ properties:
13
+ label:
14
+ type: string
15
+ id:
16
+ type: string
17
+ isSelected:
18
+ type: boolean
19
+ bgColor:
20
+ type: string
21
+ textColor:
22
+ type: string
23
+ borderColor:
24
+ type: string
25
+ selectedTab:
26
+ type: string
27
+
28
+ propsSchema:
29
+ type: object
30
+ properties:
31
+ items:
32
+ type: array
33
+ items:
34
+ type: object
35
+ properties:
36
+ label:
37
+ type: string
38
+ id:
39
+ type: string
40
+
41
+ attrsSchema:
42
+ type: object
43
+ properties:
44
+ selected-tab:
45
+ type: string
46
+
47
+ refs:
48
+ tab-*:
49
+ eventListeners:
50
+ click:
51
+ handler: handleClickItem
52
+
53
+ events:
54
+ item-click:
55
+ type: object
56
+ properties:
57
+ id:
58
+ type: string
59
+
60
+ template:
61
+ - rtgl-view d=h g=sm bgc=mu p=sm br=lg ${containerAttrString}:
62
+ - $for item in items:
63
+ - rtgl-view#tab-${item.id} data-id=${item.id} cur=p bgc=${item.bgColor} bw=xs bc=${item.borderColor} pv=md ph=lg br=lg:
64
+ - rtgl-text s=sm c=${item.textColor}: "${item.label}"
File without changes
@@ -0,0 +1,12 @@
1
+ export const INITIAL_STATE = Object.freeze({
2
+ });
3
+
4
+ export const toViewData = ({ attrs }) => {
5
+ return {
6
+ open: !!attrs.open,
7
+ x: attrs.x || 0,
8
+ y: attrs.y || 0,
9
+ placement: attrs.placement || 'top',
10
+ content: attrs.content || ''
11
+ };
12
+ }
@@ -0,0 +1,27 @@
1
+ elementName: rtgl-tooltip
2
+
3
+ viewDataSchema:
4
+ type: object
5
+
6
+ attrsSchema:
7
+ type: object
8
+ properties:
9
+ open:
10
+ type: string
11
+ x:
12
+ type: string
13
+ y:
14
+ type: string
15
+ placement:
16
+ type: string
17
+ content:
18
+ type: string
19
+
20
+ refs:
21
+ popover:
22
+
23
+ template:
24
+ - rtgl-popover#popover ?open=${open} x=${x} y=${y} placement=${placement} no-overlay:
25
+ - rtgl-view slot=content bgc=background bc=border br=md p=sm ah=c av=c:
26
+ - rtgl-text ta=c s=sm c=foreground: ${content}
27
+
@@ -0,0 +1,92 @@
1
+ export const handleAfterMount = async (deps) => {
2
+ const { props, store, render, getRefIds, } = deps;
3
+ const { waveformData } = props;
4
+
5
+ store.setWaveformData(waveformData);
6
+ render();
7
+
8
+ const canvas = getRefIds().canvas?.elm;
9
+ if (canvas) {
10
+ renderWaveform(waveformData, canvas);
11
+ }
12
+ };
13
+
14
+ export const handleOnUpdate = async (changes, deps) => {
15
+ const { store, render, getRefIds, props } = deps;
16
+ const { waveformData } = props;
17
+
18
+ if (!waveformData) {
19
+ console.log('waveform handleOnUpdate: no waveformData provided');
20
+ return;
21
+ }
22
+
23
+ store.setWaveformData(waveformData);
24
+ render();
25
+
26
+ const canvas = getRefIds().canvas?.elm;
27
+ if (canvas) {
28
+ renderWaveform(waveformData, canvas);
29
+ }
30
+ };
31
+
32
+ async function renderWaveform(waveformData, canvas) {
33
+ const ctx = canvas.getContext("2d");
34
+
35
+ // Get the actual display size of the canvas
36
+ const rect = canvas.getBoundingClientRect();
37
+ const displayWidth = rect.width;
38
+ const displayHeight = rect.height;
39
+
40
+ // Set canvas internal resolution to match display size
41
+ canvas.width = displayWidth;
42
+ canvas.height = displayHeight;
43
+
44
+ const width = canvas.width;
45
+ const height = canvas.height;
46
+
47
+ // Clear canvas
48
+ ctx.clearRect(0, 0, width, height);
49
+
50
+ // Dark theme background
51
+ ctx.fillStyle = "#1a1a1a";
52
+ ctx.fillRect(0, 0, width, height);
53
+
54
+ if (!waveformData || !waveformData.data) {
55
+ return;
56
+ }
57
+
58
+ const data = waveformData.data;
59
+ const centerY = height / 2;
60
+
61
+ // Create gradient for waveform
62
+ const gradient = ctx.createLinearGradient(0, 0, 0, height);
63
+ gradient.addColorStop(0, "#404040");
64
+ gradient.addColorStop(0.5, "#A1A1A1");
65
+ gradient.addColorStop(1, "#404040");
66
+
67
+ // Draw waveform bars
68
+ const barWidth = Math.max(1, width / data.length);
69
+ const barSpacing = 0.2; // 20% spacing between bars
70
+
71
+ for (let i = 0; i < data.length; i++) {
72
+ const amplitude = data[i];
73
+ const barHeight = amplitude * (height * 0.85);
74
+ const x = i * barWidth;
75
+ const y = centerY - barHeight / 2;
76
+
77
+ ctx.fillStyle = gradient;
78
+ ctx.fillRect(x, y, Math.max(1, barWidth * (1 - barSpacing)), barHeight);
79
+ }
80
+
81
+ // Draw subtle center line
82
+ ctx.strokeStyle = "rgba(255, 255, 255, 0.1)";
83
+ ctx.lineWidth = 1;
84
+ ctx.beginPath();
85
+ ctx.moveTo(0, centerY);
86
+ ctx.lineTo(width, centerY);
87
+ ctx.stroke();
88
+
89
+ // Add subtle glow effect
90
+ ctx.shadowBlur = 10;
91
+ ctx.shadowColor = "#2196F3";
92
+ }
@@ -0,0 +1,17 @@
1
+ export const INITIAL_STATE = Object.freeze({
2
+ waveformData: null,
3
+ });
4
+
5
+ export const setWaveformData = (state, data) => {
6
+ state.waveformData = data;
7
+ };
8
+
9
+ export const toViewData = ({ state, attrs, props }) => {
10
+ return {
11
+ isLoading: props.isLoading,
12
+ w: attrs.w || "250",
13
+ h: attrs.h || "150",
14
+ cur: attrs.cur,
15
+ waveformData: props.waveformData,
16
+ };
17
+ };
@@ -0,0 +1,38 @@
1
+ elementName: rtgl-waveform
2
+
3
+ attrsSchema:
4
+ type: object
5
+ properties:
6
+ w:
7
+ type: string
8
+ description: Width of the waveform visualizer
9
+ default: '250'
10
+ h:
11
+ type: string
12
+ description: Height of the waveform visualizer
13
+ default: '150'
14
+ cur:
15
+ type: string
16
+ description: cursor
17
+
18
+ propsSchema:
19
+ type: object
20
+ properties:
21
+ waveformData:
22
+ type: object
23
+ description: File ID of the waveform data in object storage
24
+ isLoading:
25
+ type: boolean
26
+ description: Whether the waveform data is currently being loaded
27
+
28
+ refs:
29
+ canvas:
30
+ selector: canvas
31
+
32
+ template:
33
+ - rtgl-view w=f h=f pos=rel w=${w} h=${h} cur=${cur}:
34
+ - $if isLoading:
35
+ - rtgl-view w=f h=f av=c ah=c:
36
+ - rtgl-text c=mu-fg: ...
37
+ $else:
38
+ - 'canvas#canvas style="width:100%; height:100%;"':
@@ -5,6 +5,8 @@ import RettangoliImage from './primitives/image.js';
5
5
  import RettangoliSvg from './primitives/svg.js';
6
6
  import RettangoliInput from './primitives/input.js';
7
7
  import RettangoliTextArea from './primitives/textarea.js';
8
+ import RettangoliDialog from './primitives/dialog.js';
9
+
8
10
 
9
11
  customElements.define("rtgl-button", RettangoliButton({}));
10
12
  customElements.define("rtgl-view", RettangoliView({}));
@@ -13,3 +15,4 @@ customElements.define("rtgl-image", RettangoliImage({}));
13
15
  customElements.define("rtgl-svg", RettangoliSvg({}));
14
16
  customElements.define("rtgl-input", RettangoliInput({}));
15
17
  customElements.define("rtgl-textarea", RettangoliTextArea({}));
18
+ customElements.define("rtgl-dialog", RettangoliDialog({}));
@@ -7,6 +7,8 @@ import RettangoliInput from './primitives/input.js';
7
7
  import RettangoliTextArea from './primitives/textarea.js';
8
8
  import RettangoliColorPicker from './primitives/colorPicker.js';
9
9
  import RettangoliSlider from './primitives/slider.js';
10
+ import RettangoliDialog from './primitives/dialog.js';
11
+ import RettangoliPopover from './primitives/popover.js';
10
12
 
11
13
  customElements.define("rtgl-button", RettangoliButton({}));
12
14
  customElements.define("rtgl-view", RettangoliView({}));
@@ -17,6 +19,8 @@ customElements.define("rtgl-input", RettangoliInput({}));
17
19
  customElements.define("rtgl-textarea", RettangoliTextArea({}));
18
20
  customElements.define("rtgl-color-picker", RettangoliColorPicker({}));
19
21
  customElements.define("rtgl-slider", RettangoliSlider({}));
22
+ customElements.define("rtgl-dialog", RettangoliDialog({}));
23
+ customElements.define("rtgl-popover", RettangoliPopover({}));
20
24
 
21
25
  // built from rettangoli cli fe
22
26
  import '../.temp/dynamicImport.js'
package/src/index.js CHANGED
@@ -5,6 +5,8 @@ import RettangoliImage from './primitives/image.js';
5
5
  import RettangoliSvg from './primitives/svg.js';
6
6
  import RettangoliInput from './primitives/input.js';
7
7
  import RettangoliTextArea from './primitives/textarea.js';
8
+ import RettangoliDialog from './primitives/dialog.js';
9
+ import RettangoliPopover from './primitives/popover.js';
8
10
 
9
11
  export {
10
12
  RettangoliButton,
@@ -14,4 +16,6 @@ export {
14
16
  RettangoliSvg,
15
17
  RettangoliInput,
16
18
  RettangoliTextArea,
17
- }
19
+ RettangoliDialog,
20
+ RettangoliPopover,
21
+ }
@@ -296,6 +296,16 @@ class RettangoliButtonElement extends HTMLElement {
296
296
  this._buttonElement.style.maxWidth = "";
297
297
  }
298
298
  }
299
+
300
+ // Public method to get the actual button's bounding rect
301
+ // This is needed because the host element has display: contents
302
+ getBoundingClientRect() {
303
+ if (this._buttonElement) {
304
+ return this._buttonElement.getBoundingClientRect();
305
+ }
306
+ // Fallback to host element
307
+ return super.getBoundingClientRect();
308
+ }
299
309
  }
300
310
 
301
311
  // Export factory function to maintain API compatibility
@@ -114,6 +114,15 @@ class RettangoliColorPickerElement extends HTMLElement {
114
114
  };
115
115
 
116
116
  attributeChangedCallback(name, oldValue, newValue) {
117
+ // Handle key attribute change - reset value
118
+ if (name === "key" && oldValue !== newValue) {
119
+ requestAnimationFrame(() => {
120
+ const value = this.getAttribute("value");
121
+ this._inputElement.value = value ?? "#000000";
122
+ });
123
+ return;
124
+ }
125
+
117
126
  // Handle input-specific attributes first
118
127
  if (["value", "disabled"].includes(name)) {
119
128
  this._updateInputAttributes();