@rettangoli/ui 0.1.0

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 (59) hide show
  1. package/README.md +49 -0
  2. package/dist/rettangoli-iife-layout.min.js +728 -0
  3. package/dist/rettangoli-iife-ui.min.js +830 -0
  4. package/package.json +53 -0
  5. package/src/common/BaseElement.js +182 -0
  6. package/src/common.js +190 -0
  7. package/src/components/dialog/dialog.handlers.js +5 -0
  8. package/src/components/dialog/dialog.store.js +25 -0
  9. package/src/components/dialog/dialog.view.yaml +44 -0
  10. package/src/components/dropdownMenu/dropdownMenu.handlers.js +18 -0
  11. package/src/components/dropdownMenu/dropdownMenu.store.js +25 -0
  12. package/src/components/dropdownMenu/dropdownMenu.view.yaml +54 -0
  13. package/src/components/form/form.handlers.js +63 -0
  14. package/src/components/form/form.store.js +45 -0
  15. package/src/components/form/form.view.yaml +174 -0
  16. package/src/components/navbar/navbar.examples.yaml +86 -0
  17. package/src/components/navbar/navbar.handlers.js +10 -0
  18. package/src/components/navbar/navbar.store.js +46 -0
  19. package/src/components/navbar/navbar.view.yaml +74 -0
  20. package/src/components/pageOutline/pageOutline.handlers.js +69 -0
  21. package/src/components/pageOutline/pageOutline.store.js +40 -0
  22. package/src/components/pageOutline/pageOutline.view.yaml +34 -0
  23. package/src/components/popover/popover.handlers.js +5 -0
  24. package/src/components/popover/popover.store.js +12 -0
  25. package/src/components/popover/popover.view.yaml +57 -0
  26. package/src/components/select/select.handlers.js +61 -0
  27. package/src/components/select/select.store.js +65 -0
  28. package/src/components/select/select.view.yaml +50 -0
  29. package/src/components/sidebar/sidebar.handlers.js +36 -0
  30. package/src/components/sidebar/sidebar.store.js +142 -0
  31. package/src/components/sidebar/sidebar.view.yaml +190 -0
  32. package/src/components/table/table.handlers.js +55 -0
  33. package/src/components/table/table.store.js +72 -0
  34. package/src/components/table/table.view.yaml +103 -0
  35. package/src/entry-iife-layout.js +15 -0
  36. package/src/entry-iife-ui.js +22 -0
  37. package/src/index.js +17 -0
  38. package/src/lib/uhtml.js +9 -0
  39. package/src/primitives/button.js +306 -0
  40. package/src/primitives/colorPicker.js +213 -0
  41. package/src/primitives/image.js +234 -0
  42. package/src/primitives/input.js +218 -0
  43. package/src/primitives/slider.js +269 -0
  44. package/src/primitives/svg.js +95 -0
  45. package/src/primitives/text.js +141 -0
  46. package/src/primitives/textarea.js +103 -0
  47. package/src/primitives/view.js +217 -0
  48. package/src/setup.js +16 -0
  49. package/src/styles/anchorStyles.js +13 -0
  50. package/src/styles/buttonMarginStyles.js +84 -0
  51. package/src/styles/cursorStyles.js +12 -0
  52. package/src/styles/flexChildStyles.js +43 -0
  53. package/src/styles/flexDirectionStyles.js +74 -0
  54. package/src/styles/marginStyles.js +13 -0
  55. package/src/styles/paddingSvgStyles.js +120 -0
  56. package/src/styles/scrollStyles.js +22 -0
  57. package/src/styles/textColorStyles.js +14 -0
  58. package/src/styles/textStyles.js +62 -0
  59. package/src/styles/viewStyles.js +114 -0
@@ -0,0 +1,174 @@
1
+ elementName: rtgl-form
2
+
3
+ viewDataSchema:
4
+ type: object
5
+
6
+ propsSchema:
7
+ type: object
8
+ properties:
9
+ defaultValues:
10
+ type: object
11
+ form:
12
+ type: object
13
+ properties:
14
+ title:
15
+ type: string
16
+ description:
17
+ type: string
18
+ fields:
19
+ type: array
20
+ items:
21
+ anyOf:
22
+ - type: object
23
+ properties:
24
+ id:
25
+ type: string
26
+ label:
27
+ type: string
28
+ description:
29
+ type: string
30
+ inputType:
31
+ const: inputText
32
+ placeholder:
33
+ type: string
34
+ required:
35
+ - id
36
+ - label
37
+ - inputType
38
+ additionalProperties: false
39
+ - type: object
40
+ properties:
41
+ id:
42
+ type: string
43
+ label:
44
+ type: string
45
+ description:
46
+ type: string
47
+ inputType:
48
+ const: select
49
+ placeholder:
50
+ type: string
51
+ options:
52
+ type: array
53
+ items:
54
+ type: object
55
+ properties:
56
+ id:
57
+ type: string
58
+ label:
59
+ type: string
60
+ value:
61
+ type: any
62
+ required:
63
+ - id
64
+ - label
65
+ - value
66
+ required:
67
+ - id
68
+ - label
69
+ - inputType
70
+ - options
71
+ additionalProperties: false
72
+ - type: object
73
+ properties:
74
+ id:
75
+ type: string
76
+ label:
77
+ type: string
78
+ description:
79
+ type: string
80
+ inputType:
81
+ const: colorPicker
82
+ value:
83
+ type: string
84
+ required:
85
+ - id
86
+ - label
87
+ - inputType
88
+ additionalProperties: false
89
+ - type: object
90
+ properties:
91
+ id:
92
+ type: string
93
+ label:
94
+ type: string
95
+ description:
96
+ type: string
97
+ inputType:
98
+ const: slider
99
+ min:
100
+ type: number
101
+ max:
102
+ type: number
103
+ step:
104
+ type: number
105
+ value:
106
+ type: number
107
+ required:
108
+ - id
109
+ - label
110
+ - inputType
111
+ additionalProperties: false
112
+ actions:
113
+ type: object
114
+ properties:
115
+ buttons:
116
+ type: array
117
+ items:
118
+ type: object
119
+ properties:
120
+ id:
121
+ type: string
122
+ content:
123
+ type: string
124
+ required:
125
+ - id
126
+ - content
127
+
128
+ refs:
129
+ action-*:
130
+ eventListeners:
131
+ click:
132
+ handler: handleActionClick
133
+ input-*:
134
+ eventListeners:
135
+ input-keydown:
136
+ handler: handleInputChange
137
+ select-*:
138
+ eventListeners:
139
+ select-change:
140
+ handler: handleSelectChange
141
+ colorpicker-*:
142
+ eventListeners:
143
+ colorpicker-change:
144
+ handler: handleColorPickerChange
145
+ slider-*:
146
+ eventListeners:
147
+ slider-change:
148
+ handler: handleSliderChange
149
+
150
+ events: {}
151
+
152
+ template:
153
+ - rtgl-view w=f h=f p=md g=lg ${containerAttrString}:
154
+ - rtgl-view g=sm w=f:
155
+ - rtgl-text s=lg: ${title}
156
+ - rtgl-text c=mu-fg: ${description}
157
+ - rtgl-view g=lg w=f:
158
+ - $for field, i in fields:
159
+ - rtgl-view g=md w=f:
160
+ - rtgl-view g=sm:
161
+ - rtgl-text: ${field.label}
162
+ - rtgl-text s=sm c=mu-fg: ${field.description}
163
+ - $if field.inputType == "inputText":
164
+ - rtgl-input#input-${field.id} w=f placeholder=${field.placeholder}:
165
+ - $if field.inputType == "select":
166
+ - rtgl-select#select-${field.id} w=f .options=fields[${i}].options .placeholder=fields[${i}].placeholder .selectedValue=formValues[field.id]:
167
+ - $if field.inputType == "colorPicker":
168
+ - rtgl-color-picker#colorpicker-${field.id} value=${field.value}:
169
+ - $if field.inputType == "slider":
170
+ - rtgl-slider#slider-${field.id} min=${field.min} max=${field.max} step=${field.step} value=${field.value}:
171
+ - rtgl-view g=sm w=f:
172
+ - $for button, i in actions.buttons:
173
+ - rtgl-view d=h ah=e g=sm w=f:
174
+ - rtgl-button#action-${button.id}: ${button.content}
@@ -0,0 +1,86 @@
1
+ config: {}
2
+
3
+ ---
4
+ name: 'basic_with_href'
5
+ viewData:
6
+ start:
7
+ label: "My App"
8
+ href: "/"
9
+
10
+ ---
11
+ name: 'with_path_navigation'
12
+ viewData:
13
+ start:
14
+ label: "Dashboard"
15
+ path: "/dashboard"
16
+
17
+ ---
18
+ name: 'with_logo_image'
19
+ viewData:
20
+ start:
21
+ label: "Company Name"
22
+ image:
23
+ src: "/logo.png"
24
+ width: 32
25
+ height: 32
26
+ alt: "Company Logo"
27
+
28
+ ---
29
+ name: 'with_logo_and_href'
30
+ viewData:
31
+ start:
32
+ label: "Rettangoli"
33
+ href: "/"
34
+ image:
35
+ src: "/assets/logo.svg"
36
+ width: 40
37
+ height: 40
38
+ alt: "Rettangoli Logo"
39
+
40
+ ---
41
+ name: 'with_logo_and_path'
42
+ viewData:
43
+ start:
44
+ label: "Project Hub"
45
+ path: "/projects"
46
+ image:
47
+ src: "/icons/hub.png"
48
+ width: 28
49
+ height: 28
50
+ alt: "Hub Icon"
51
+
52
+ ---
53
+ name: 'text_only_no_navigation'
54
+ viewData:
55
+ start:
56
+ label: "Static Header"
57
+
58
+ ---
59
+ name: 'long_label_with_image'
60
+ viewData:
61
+ start:
62
+ label: "Enterprise Resource Planning System"
63
+ image:
64
+ src: "/brand/enterprise-logo.jpg"
65
+ width: 36
66
+ height: 36
67
+ alt: "Enterprise Logo"
68
+
69
+ ---
70
+ name: 'minimal_brand'
71
+ viewData:
72
+ start:
73
+ label: "Brand"
74
+ href: "/home"
75
+
76
+ ---
77
+ name: 'app_with_square_logo'
78
+ viewData:
79
+ start:
80
+ label: "TaskFlow"
81
+ path: "/tasks"
82
+ image:
83
+ src: "/logos/taskflow-square.png"
84
+ width: 30
85
+ height: 30
86
+ alt: "TaskFlow Square Logo"
@@ -0,0 +1,10 @@
1
+
2
+ export const handleClickStart = (e, deps) => {
3
+ const { dispatchEvent, store } = deps;
4
+ console.log('handle click start', store.selectPath());
5
+ dispatchEvent(new CustomEvent('clickStart', {
6
+ detail: {
7
+ path: store.selectPath(),
8
+ }
9
+ }));
10
+ }
@@ -0,0 +1,46 @@
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
+ console.log('attrs', {
11
+ attrs,
12
+ entries: Object.entries(attrs)
13
+ })
14
+
15
+ const attrsStart = attrs.start ? JSON.parse(decodeURIComponent(attrs.start)) : props.start;
16
+
17
+ const containerAttrString = stringifyAttrs(attrs);
18
+ const start = attrsStart || {
19
+ label: '',
20
+ // href: undefined,
21
+ // path: undefined,
22
+ image: {
23
+ src: '',
24
+ width: 32,
25
+ height: 32,
26
+ alt: ''
27
+ }
28
+ }
29
+ // start.hasImage = start.image && start.image.src;
30
+ // start.hasHref = !!start.href;
31
+ return {
32
+ containerAttrString,
33
+ start
34
+ };
35
+ }
36
+
37
+ export const selectPath = ({ props }) => {
38
+ return props.start.path;
39
+ }
40
+
41
+ export const setState = (state) => {
42
+ // do doSomething
43
+ }
44
+
45
+
46
+
@@ -0,0 +1,74 @@
1
+ elementName: rtgl-navbar
2
+
3
+ viewDataSchema:
4
+ type: object
5
+ properties:
6
+ containerAttrString:
7
+ type: string
8
+ start:
9
+ type: object
10
+ properties:
11
+ label:
12
+ type: string
13
+ href:
14
+ type: string
15
+ image:
16
+ type: object
17
+ properties:
18
+ src:
19
+ type: string
20
+ hasImage:
21
+ type: boolean
22
+ hasHref:
23
+ type: boolean
24
+
25
+ propsSchema:
26
+ type: object
27
+ properties:
28
+ start:
29
+ type: object
30
+ properties:
31
+ label:
32
+ type: string
33
+ href:
34
+ type: string
35
+ image:
36
+ type: object
37
+ properties:
38
+ src:
39
+ type: string
40
+
41
+ refs:
42
+ start:
43
+ eventListeners:
44
+ click:
45
+ handler: handleClickStart
46
+
47
+ events:
48
+ clickStart:
49
+ type: object
50
+ properties:
51
+ path:
52
+ type: string
53
+
54
+ anchors:
55
+ - &image
56
+ - rtgl-text s=lg: "${start.label}"
57
+ - $if start.image && start.image.src:
58
+ - rtgl-image w=${start.image.width} h=${start.image.height} src=${start.image.src} alt=${start.image.alt}:
59
+
60
+ template:
61
+ - rtgl-view bgc=bg d=h h=48 av=c w=f ${containerAttrString}:
62
+ - $if start.href:
63
+ - a href=${start.href}:
64
+ - rtgl-view d=h av=c g=lg g=md:
65
+ - *image
66
+ $elif start.path:
67
+ - rtgl-view#start d=h av=c g=lg g=md cur=p:
68
+ - *image
69
+ $else:
70
+ - rtgl-view d=h av=c g=lg g=md:
71
+ - *image
72
+ - rtgl-view flex=1:
73
+ - rtgl-view d=h av=c g=lg:
74
+ - slot name=right:
@@ -0,0 +1,69 @@
1
+
2
+
3
+ /**
4
+ *
5
+ * @param {*} headingElements
6
+ * @param {*} deps
7
+ */
8
+ const updateToLatestCurrentId = (headingElements, deps) => {
9
+ const { store, render } = deps;
10
+
11
+ let currentHeadingId;
12
+ let closestTopPosition = -Infinity;
13
+
14
+ headingElements.forEach((heading) => {
15
+ const rect = heading.getBoundingClientRect();
16
+
17
+ if (rect.top <= 20) {
18
+ if (rect.top > closestTopPosition) {
19
+ closestTopPosition = rect.top;
20
+ currentHeadingId = heading.id;
21
+ }
22
+ }
23
+ });
24
+
25
+ if (currentHeadingId && currentHeadingId !== store.selectCurrentId()) {
26
+ store.setCurrentId(currentHeadingId);
27
+ render();
28
+ }
29
+ };
30
+
31
+ const startListening = (contentContainer, deps) => {
32
+ const { store, render } = deps;
33
+
34
+ // Extract headings
35
+ const headings = contentContainer.querySelectorAll("rtgl-text[id]");
36
+ const headingElements = Array.from(headings);
37
+
38
+ const items = headingElements.map((heading) => ({
39
+ id: heading.id,
40
+ href: `#${heading.id}`,
41
+ title: heading.textContent
42
+ }));
43
+
44
+ store.setItems(items);
45
+ updateToLatestCurrentId(headingElements, deps);
46
+ render();
47
+
48
+ const boundCheckCurrentHeading = updateToLatestCurrentId.bind(this, headingElements, deps);
49
+
50
+ // Add scroll listener to the content container
51
+ contentContainer.addEventListener("scroll", boundCheckCurrentHeading, {
52
+ passive: true,
53
+ });
54
+
55
+ return () => {
56
+ contentContainer.removeEventListener("scroll", boundCheckCurrentHeading);
57
+ }
58
+ };
59
+
60
+ export const handleOnMount = (deps) => {
61
+ const { attrs } = deps;
62
+ requestAnimationFrame(() => {
63
+ const targetElement = document.getElementById(attrs['target-id'])
64
+ const stopListening = startListening(targetElement, deps)
65
+ return () => {
66
+ stopListening();
67
+ }
68
+ })
69
+ }
@@ -0,0 +1,40 @@
1
+ export const INITIAL_STATE = Object.freeze({
2
+ items: [],
3
+ currentId: null,
4
+ contentContainer: null
5
+ });
6
+
7
+ export const toViewData = ({ state }) => {
8
+ return {
9
+ items: state.items.map((item) => {
10
+ return {
11
+ ...item,
12
+ c: item.id === state.currentId ? 'fg' : 'mu-fg'
13
+ }
14
+ }),
15
+ currentId: state.currentId
16
+ };
17
+ }
18
+
19
+ export const selectState = ({ state }) => {
20
+ return state;
21
+ }
22
+
23
+ export const selectCurrentId = ({ state }) => {
24
+ return state.currentId;
25
+ }
26
+
27
+ export const setItems = (state, items) => {
28
+ state.items = items;
29
+ }
30
+
31
+ export const setCurrentId = (state, id) => {
32
+ state.currentId = id;
33
+ }
34
+
35
+ export const setContentContainer = (state, container) => {
36
+ state.contentContainer = container;
37
+ }
38
+
39
+
40
+
@@ -0,0 +1,34 @@
1
+ elementName: rtgl-page-outline
2
+
3
+ viewDataSchema:
4
+ type: object
5
+ properties:
6
+ items:
7
+ type: array
8
+ items:
9
+ type: object
10
+ properties:
11
+ slug:
12
+ type: string
13
+ title:
14
+ type: string
15
+ selectedSlug:
16
+ type: string
17
+ nullable: true
18
+
19
+ propsSchema:
20
+ type: object
21
+ properties: {}
22
+
23
+ refs: {}
24
+
25
+ events:
26
+ onItemClick:
27
+ type: object
28
+
29
+ template:
30
+ - rtgl-view h=f w=272:
31
+ - rtgl-view w=f g=sm mt=xl:
32
+ - $for item, i in items:
33
+ - rtgl-view pv=xs av=c href=${item.href}:
34
+ - rtgl-text s=sm c=${item.c} h-c=fg: ${item.title}
@@ -0,0 +1,5 @@
1
+
2
+ export const handleClickOverlay = (e, deps) => {
3
+ const { dispatchEvent } = deps;
4
+ dispatchEvent(new CustomEvent('click-overlay'));
5
+ }
@@ -0,0 +1,12 @@
1
+ export const INITIAL_STATE = Object.freeze({});
2
+
3
+ export const toViewData = ({ state, props }) => {
4
+ return {
5
+ isOpen: props.isOpen,
6
+ position: props.position,
7
+ };
8
+ }
9
+
10
+ export const selectState = ({ state }) => {
11
+ return state;
12
+ }
@@ -0,0 +1,57 @@
1
+ elementName: rtgl-popover
2
+
3
+ viewDataSchema:
4
+ type: object
5
+ properties:
6
+ isOpen:
7
+ type: boolean
8
+ position:
9
+ type: object
10
+ properties:
11
+ x:
12
+ type: number
13
+ y:
14
+ type: number
15
+ placement:
16
+ type: string
17
+
18
+ propsSchema:
19
+ type: object
20
+ properties:
21
+ placement:
22
+ type: string
23
+ default: bottom
24
+ isOpen:
25
+ type: boolean
26
+ position:
27
+ type: object
28
+ properties:
29
+ x:
30
+ type: number
31
+ y:
32
+ type: number
33
+
34
+ refs:
35
+ popoverOverlay:
36
+ eventListeners:
37
+ click:
38
+ handler: handleClickOverlay
39
+
40
+ styles:
41
+ '@keyframes popover-in':
42
+ from:
43
+ opacity: 0
44
+ transform: scale(0.95)
45
+ to:
46
+ opacity: 1
47
+ transform: scale(1)
48
+
49
+ '#popoverContainer':
50
+ animation: popover-in 150ms cubic-bezier(0.16, 1, 0.3, 1)
51
+ transform-origin: top
52
+
53
+ template:
54
+ - $if isOpen:
55
+ - rtgl-view#popoverOverlay pos=fix cor=full:
56
+ - 'rtgl-view#popoverContainer pos=fix style="left: ${position.x}px; top: ${position.y}px;" id=floatingElement bw=xs p=md bgc=mu':
57
+ - slot name=content:
@@ -0,0 +1,61 @@
1
+
2
+ export const handleOnMount = (deps) => {
3
+ const { store, props, render } = deps;
4
+
5
+ if (props.selectedValue !== null && props.selectedValue !== undefined && props.options) {
6
+ const selectedOption = props.options.find(opt => opt.value === props.selectedValue);
7
+ if (selectedOption) {
8
+ store.update((state) => {
9
+ state.selectedValue = selectedOption.value;
10
+ state.selectedLabel = selectedOption.label;
11
+ });
12
+ render();
13
+ }
14
+ }
15
+ }
16
+
17
+ export const handleButtonClick = (e, deps) => {
18
+ const { store, render, getRefIds } = deps;
19
+ store.openOptionsPopover({
20
+ position: {
21
+ y: e.clientY,
22
+ x: e.clientX,
23
+ }
24
+ })
25
+ render();
26
+ }
27
+
28
+ export const handleClickOptionsPopoverOverlay = (e, deps) => {
29
+ const { store, render } = deps;
30
+ store.closeOptionsPopover();
31
+ render();
32
+ }
33
+
34
+ export const handleOptionClick = (e, deps) => {
35
+ const { render, dispatchEvent, props, store } = deps;
36
+ const id = e.currentTarget.id.replace('option-', '');
37
+
38
+ const option = props.options[id];
39
+
40
+ // Update internal state
41
+ store.updateSelectOption(option);
42
+
43
+ // Call onChange if provided
44
+ if (props.onChange && typeof props.onChange === 'function') {
45
+ props.onChange(option.value);
46
+ }
47
+
48
+ // Dispatch custom event for backward compatibility
49
+ dispatchEvent(new CustomEvent('option-selected', {
50
+ detail: { value: option.value, label: option.label },
51
+ bubbles: true
52
+ }));
53
+
54
+ // Also dispatch select-change event to match form's event listener pattern
55
+ dispatchEvent(new CustomEvent('select-change', {
56
+ detail: { selectedValue: option.value },
57
+ bubbles: true
58
+ }));
59
+
60
+ render();
61
+ }