@pictogrammers/components 0.3.2 → 0.4.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 (294) hide show
  1. package/README.md +11 -12
  2. package/favicon.svg +20 -0
  3. package/index.html +67 -49
  4. package/main.js +2 -0
  5. package/main.js.LICENSE.txt +10 -0
  6. package/package.json +6 -6
  7. package/pg/annoy/README.md +0 -5
  8. package/pg/annoy/__examples__/basic/basic.css +3 -0
  9. package/pg/annoy/__examples__/basic/basic.html +4 -7
  10. package/pg/annoy/__examples__/basic/basic.ts +3 -1
  11. package/pg/annoy/annoy.css +29 -198
  12. package/pg/annoy/annoy.html +5 -56
  13. package/pg/annoy/annoy.ts +4 -25
  14. package/pg/app/README.md +11 -0
  15. package/pg/app/__examples__/basic/basic.css +8 -0
  16. package/pg/app/__examples__/basic/basic.html +15 -0
  17. package/pg/app/__examples__/basic/basic.ts +13 -0
  18. package/pg/app/app.css +108 -0
  19. package/pg/app/app.html +16 -0
  20. package/pg/app/app.ts +45 -0
  21. package/pg/app/index.ts +3 -0
  22. package/pg/avatar/__examples__/basic/basic.ts +5 -3
  23. package/pg/button/README.md +3 -0
  24. package/pg/button/button.css +13 -12
  25. package/pg/button/button.spec.ts +35 -0
  26. package/pg/button/button.ts +17 -12
  27. package/pg/buttonLink/buttonLink.css +3 -2
  28. package/pg/buttonMenu/README.md +54 -0
  29. package/pg/buttonMenu/__examples__/basic/basic.html +6 -0
  30. package/pg/buttonMenu/__examples__/basic/basic.ts +43 -0
  31. package/pg/buttonMenu/buttonMenu.css +12 -0
  32. package/pg/buttonMenu/buttonMenu.html +4 -0
  33. package/pg/buttonMenu/buttonMenu.ts +63 -0
  34. package/pg/buttonMenu/index.ts +3 -0
  35. package/pg/buttonToggle/__examples__/basic/basic.ts +2 -2
  36. package/pg/buttonToggle/__examples__/persist/persist.html +10 -0
  37. package/pg/buttonToggle/__examples__/persist/persist.ts +35 -0
  38. package/pg/cardUser/__examples__/basic/basic.ts +0 -1
  39. package/pg/cardUser/cardUser.css +2 -10
  40. package/pg/cardUser/cardUser.html +0 -5
  41. package/pg/cardUser/cardUser.ts +0 -6
  42. package/pg/database/README.md +1 -1
  43. package/pg/database/__examples__/basic/basic.html +2 -1
  44. package/pg/database/__examples__/basic/basic.ts +3 -3
  45. package/pg/dropdown/dropdown.ts +0 -19
  46. package/pg/grid/__examples__/basic/basic.html +2 -2
  47. package/pg/grid/__examples__/basic/basic.ts +3 -2
  48. package/pg/grid/grid.ts +0 -1
  49. package/pg/icon/README.md +6 -5
  50. package/pg/icon/__examples__/basic/basic.html +2 -2
  51. package/pg/icon/__examples__/basic/basic.ts +1 -1
  52. package/pg/icon/icon.ts +6 -0
  53. package/pg/inputCheckList/__examples__/basic/basic.ts +5 -5
  54. package/pg/inputCheckList/inputCheckList.ts +2 -0
  55. package/pg/inputFileLocal/inputFileLocal.css +3 -2
  56. package/pg/inputPixelEditor/README.md +132 -0
  57. package/pg/inputPixelEditor/__examples__/basic/basic.css +29 -0
  58. package/pg/inputPixelEditor/__examples__/basic/basic.html +63 -0
  59. package/pg/inputPixelEditor/__examples__/basic/basic.ts +200 -0
  60. package/pg/inputPixelEditor/__examples__/basic/openUtils.ts +41 -0
  61. package/pg/inputPixelEditor/__examples__/basic/saveUtil.ts +35 -0
  62. package/pg/inputPixelEditor/index.ts +3 -0
  63. package/pg/inputPixelEditor/inputPixelEditor.css +27 -0
  64. package/pg/inputPixelEditor/inputPixelEditor.html +3 -0
  65. package/pg/inputPixelEditor/inputPixelEditor.ts +839 -0
  66. package/pg/inputPixelEditor/utils/bitmapToMask.ts +202 -0
  67. package/pg/inputPixelEditor/utils/cloneGrid.ts +17 -0
  68. package/pg/inputPixelEditor/utils/constants.ts +1 -0
  69. package/pg/inputPixelEditor/utils/createLayer.ts +8 -0
  70. package/pg/inputPixelEditor/utils/debounce.ts +5 -0
  71. package/pg/inputPixelEditor/utils/diffGrid.ts +26 -0
  72. package/pg/inputPixelEditor/utils/fillGrid.ts +11 -0
  73. package/pg/inputPixelEditor/utils/getEllipseOutlinePixels.ts +105 -0
  74. package/pg/inputPixelEditor/utils/getEllipsePixels.ts +28 -0
  75. package/pg/inputPixelEditor/utils/getGuides.ts +232 -0
  76. package/pg/inputPixelEditor/utils/getLinePixels.ts +18 -0
  77. package/pg/inputPixelEditor/utils/getRectangleOutlinePixels.ts +20 -0
  78. package/pg/inputPixelEditor/utils/getRectanglePixels.ts +15 -0
  79. package/pg/inputPixelEditor/utils/inputMode.ts +8 -0
  80. package/pg/inputPixelEditor/utils/interateGrid.ts +7 -0
  81. package/pg/inputPixelEditor/utils/isEmptyGrid.ts +3 -0
  82. package/pg/inputPixelEditor/utils/maskToBitmap.ts +66 -0
  83. package/pg/inputRange/__examples__/basic/basic.ts +4 -4
  84. package/pg/inputRange/inputRange.ts +6 -4
  85. package/pg/inputSelect/README.md +1 -1
  86. package/pg/inputSelect/__examples__/basic/basic.ts +7 -5
  87. package/pg/inputSelect/inputSelect.css +15 -12
  88. package/pg/inputSelect/inputSelect.html +3 -3
  89. package/pg/inputSelect/inputSelect.ts +33 -30
  90. package/pg/inputText/__examples__/basic/basic.ts +6 -6
  91. package/pg/inputText/inputText.css +1 -0
  92. package/pg/inputUserSelect/README.md +1 -1
  93. package/pg/inputUserSelect/inputUserSelect.ts +1 -1
  94. package/pg/listTag/__examples__/basic/basic.ts +4 -5
  95. package/pg/markdown/README.md +17 -3
  96. package/pg/markdown/__examples__/basic/basic.ts +2 -2
  97. package/pg/markdown/__examples__/basic/constants.ts +1 -1
  98. package/pg/markdown/markdown.css +11 -0
  99. package/pg/menu/README.md +46 -0
  100. package/pg/menu/__examples__/basic/basic.html +6 -0
  101. package/pg/menu/__examples__/basic/basic.ts +46 -0
  102. package/pg/menu/index.ts +3 -0
  103. package/pg/menu/menu.css +19 -0
  104. package/pg/menu/menu.html +1 -0
  105. package/pg/menu/menu.ts +119 -0
  106. package/pg/menuDivider/README.md +7 -0
  107. package/pg/menuDivider/__examples__/basic/basic.html +3 -0
  108. package/pg/menuDivider/__examples__/basic/basic.ts +28 -0
  109. package/pg/menuDivider/index.ts +3 -0
  110. package/pg/menuDivider/menuDivider.css +9 -0
  111. package/pg/menuDivider/menuDivider.html +1 -0
  112. package/pg/menuDivider/menuDivider.ts +22 -0
  113. package/pg/menuIcon/menuIcon.ts +43 -36
  114. package/pg/menuItem/README.md +32 -0
  115. package/pg/menuItem/__examples__/basic/basic.html +26 -0
  116. package/pg/menuItem/__examples__/basic/basic.ts +41 -0
  117. package/pg/menuItem/index.ts +3 -0
  118. package/pg/menuItem/menuItem.css +97 -0
  119. package/pg/menuItem/menuItem.html +1 -0
  120. package/pg/menuItem/menuItem.ts +77 -0
  121. package/pg/menuItemIcon/README.md +32 -0
  122. package/pg/menuItemIcon/__examples__/basic/basic.html +34 -0
  123. package/pg/menuItemIcon/__examples__/basic/basic.ts +55 -0
  124. package/pg/menuItemIcon/index.ts +3 -0
  125. package/pg/menuItemIcon/menuItemIcon.css +106 -0
  126. package/pg/menuItemIcon/menuItemIcon.html +4 -0
  127. package/pg/menuItemIcon/menuItemIcon.ts +156 -0
  128. package/pg/modalAlert/__examples__/basic/basic.ts +1 -1
  129. package/pg/modalAlert/modalAlert.css +1 -4
  130. package/pg/modalAlert/modalAlert.ts +18 -4
  131. package/pg/modification/__examples__/basic/basic.ts +1 -2
  132. package/pg/modification/__examples__/basic/constants.ts +25 -50
  133. package/pg/modification/modification.ts +1 -1
  134. package/pg/overlay/overlay.ts +13 -12
  135. package/pg/overlayContextMenu/README.md +35 -0
  136. package/pg/overlayContextMenu/__examples__/basic/basic.css +23 -0
  137. package/pg/overlayContextMenu/__examples__/basic/basic.html +7 -0
  138. package/pg/overlayContextMenu/__examples__/basic/basic.ts +87 -0
  139. package/pg/overlayContextMenu/index.ts +3 -0
  140. package/pg/overlayContextMenu/overlayContextMenu.css +16 -0
  141. package/pg/overlayContextMenu/overlayContextMenu.html +3 -0
  142. package/pg/overlayContextMenu/overlayContextMenu.ts +98 -0
  143. package/pg/overlayMenu/README.md +33 -0
  144. package/pg/overlayMenu/__examples__/basic/basic.css +3 -0
  145. package/pg/overlayMenu/__examples__/basic/basic.html +5 -0
  146. package/pg/overlayMenu/__examples__/basic/basic.ts +62 -0
  147. package/pg/overlayMenu/index.ts +3 -0
  148. package/pg/overlayMenu/overlayMenu.css +16 -0
  149. package/pg/overlayMenu/overlayMenu.html +3 -0
  150. package/pg/overlayMenu/overlayMenu.ts +67 -0
  151. package/pg/overlaySelectMenu/README.md +33 -0
  152. package/pg/overlaySelectMenu/__examples__/basic/basic.css +3 -0
  153. package/pg/overlaySelectMenu/__examples__/basic/basic.html +5 -0
  154. package/pg/overlaySelectMenu/__examples__/basic/basic.ts +62 -0
  155. package/pg/overlaySelectMenu/index.ts +3 -0
  156. package/pg/overlaySelectMenu/overlaySelectMenu.css +17 -0
  157. package/pg/overlaySelectMenu/overlaySelectMenu.html +3 -0
  158. package/pg/overlaySelectMenu/overlaySelectMenu.ts +96 -0
  159. package/pg/overlaySubMenu/README.md +35 -0
  160. package/pg/overlaySubMenu/index.ts +3 -0
  161. package/pg/overlaySubMenu/overlaySubMenu.css +27 -0
  162. package/pg/overlaySubMenu/overlaySubMenu.html +3 -0
  163. package/pg/overlaySubMenu/overlaySubMenu.ts +103 -0
  164. package/pg/picker/picker.ts +1 -19
  165. package/pg/scroll/__examples__/basic/basic.ts +1 -1
  166. package/pg/search/__examples__/basic/basic.ts +10 -7
  167. package/pg/search/search.css +2 -2
  168. package/pg/shared/models/user.ts +0 -2
  169. package/pg/tab/tab.ts +0 -10
  170. package/pg/tabs/partials/tab.css +42 -0
  171. package/pg/tabs/partials/tab.ts +70 -0
  172. package/pg/tabs/tabs.css +0 -53
  173. package/pg/tabs/tabs.ts +54 -70
  174. package/pg/toast/README.md +35 -6
  175. package/pg/toast/__examples__/basic/basic.html +7 -0
  176. package/pg/toast/__examples__/basic/basic.ts +76 -0
  177. package/pg/toast/toast.css +3 -0
  178. package/pg/toast/toast.ts +20 -4
  179. package/pg/tooltip/addTooltip.ts +3 -1
  180. package/pg/tooltip/tooltip.ts +1 -1
  181. package/pg/tree/README.md +67 -0
  182. package/pg/tree/__examples__/basic/basic.html +10 -0
  183. package/pg/tree/__examples__/basic/basic.ts +162 -0
  184. package/pg/tree/index.ts +3 -0
  185. package/pg/tree/tree.css +28 -0
  186. package/pg/tree/tree.html +1 -0
  187. package/pg/tree/tree.ts +217 -0
  188. package/pg/treeButtonIcon/README.md +39 -0
  189. package/pg/treeButtonIcon/index.ts +3 -0
  190. package/pg/treeButtonIcon/treeButtonIcon.css +18 -0
  191. package/pg/treeButtonIcon/treeButtonIcon.html +3 -0
  192. package/pg/treeButtonIcon/treeButtonIcon.ts +42 -0
  193. package/pg/treeItem/README.md +3 -0
  194. package/pg/treeItem/index.ts +3 -0
  195. package/pg/treeItem/treeItem.css +263 -0
  196. package/pg/treeItem/treeItem.html +16 -0
  197. package/pg/treeItem/treeItem.ts +558 -0
  198. package/pgAnnoy.js +1 -0
  199. package/pgApp.js +1 -0
  200. package/pgAvatar.js +1 -0
  201. package/pgButton.js +1 -0
  202. package/pgButtonGroup.js +1 -0
  203. package/pgButtonLink.js +1 -0
  204. package/pgButtonMenu.js +1 -0
  205. package/pgButtonToggle.js +1 -0
  206. package/pgCard.js +1 -0
  207. package/pgCardUser.js +1 -0
  208. package/pgColor.js +1 -0
  209. package/pgDatabase.js +1 -0
  210. package/pgDropdown.js +1 -0
  211. package/pgGrid.js +1 -0
  212. package/pgHeader.js +1 -0
  213. package/pgIcon.js +1 -0
  214. package/pgInputCheck.js +1 -0
  215. package/pgInputCheckList.js +1 -0
  216. package/pgInputFileLocal.js +1 -0
  217. package/pgInputHexRgb.js +1 -0
  218. package/pgInputPixelEditor.js +1 -0
  219. package/pgInputRange.js +1 -0
  220. package/pgInputSelect.js +1 -0
  221. package/pgInputText.js +1 -0
  222. package/pgInputTextIcon.js +1 -0
  223. package/pgInputUserSelect.js +1 -0
  224. package/pgListTag.js +1 -0
  225. package/pgMarkdown.js +2 -0
  226. package/pgMarkdown.js.LICENSE.txt +10 -0
  227. package/pgMenu.js +1 -0
  228. package/pgMenuDivider.js +1 -0
  229. package/pgMenuIcon.js +1 -0
  230. package/pgMenuItem.js +1 -0
  231. package/pgMenuItemIcon.js +1 -0
  232. package/pgModalAlert.js +1 -0
  233. package/pgModification.js +1 -0
  234. package/pgNav.js +1 -0
  235. package/pgOverlay.js +1 -0
  236. package/pgOverlayContextMenu.js +1 -0
  237. package/pgOverlayMenu.js +1 -0
  238. package/pgOverlaySelectMenu.js +1 -0
  239. package/pgOverlaySubMenu.js +1 -0
  240. package/pgPicker.js +1 -0
  241. package/pgPreview.js +1 -0
  242. package/pgScroll.js +1 -0
  243. package/pgSearch.js +1 -0
  244. package/pgTab.js +1 -0
  245. package/pgTabs.js +1 -0
  246. package/pgToast.js +1 -0
  247. package/pgToasts.js +1 -0
  248. package/pgTooltip.js +1 -0
  249. package/pgTree.js +1 -0
  250. package/pgTreeButtonIcon.js +1 -0
  251. package/pgTreeItem.js +1 -0
  252. package/theme-ui3.css +31 -0
  253. package/@types/css.d.ts +0 -4
  254. package/@types/html.d.ts +0 -4
  255. package/dist/main.js +0 -3819
  256. package/dist/pgAnnoy.js +0 -116
  257. package/dist/pgAvatar.js +0 -136
  258. package/dist/pgButton.js +0 -116
  259. package/dist/pgButtonGroup.js +0 -116
  260. package/dist/pgButtonLink.js +0 -116
  261. package/dist/pgButtonToggle.js +0 -146
  262. package/dist/pgCard.js +0 -116
  263. package/dist/pgCardUser.js +0 -196
  264. package/dist/pgColor.js +0 -136
  265. package/dist/pgDatabase.js +0 -236
  266. package/dist/pgDropdown.js +0 -686
  267. package/dist/pgGrid.js +0 -126
  268. package/dist/pgHeader.js +0 -116
  269. package/dist/pgIcon.js +0 -116
  270. package/dist/pgInputCheck.js +0 -116
  271. package/dist/pgInputCheckList.js +0 -126
  272. package/dist/pgInputFileLocal.js +0 -116
  273. package/dist/pgInputHexRgb.js +0 -126
  274. package/dist/pgInputRange.js +0 -116
  275. package/dist/pgInputSelect.js +0 -116
  276. package/dist/pgInputText.js +0 -116
  277. package/dist/pgInputTextIcon.js +0 -176
  278. package/dist/pgInputUserSelect.js +0 -116
  279. package/dist/pgListTag.js +0 -136
  280. package/dist/pgMarkdown.js +0 -346
  281. package/dist/pgMenuIcon.js +0 -206
  282. package/dist/pgModalAlert.js +0 -126
  283. package/dist/pgModification.js +0 -396
  284. package/dist/pgNav.js +0 -116
  285. package/dist/pgOverlay.js +0 -96
  286. package/dist/pgPicker.js +0 -116
  287. package/dist/pgPreview.js +0 -116
  288. package/dist/pgScroll.js +0 -266
  289. package/dist/pgSearch.js +0 -146
  290. package/dist/pgTab.js +0 -116
  291. package/dist/pgTabs.js +0 -136
  292. package/dist/pgToast.js +0 -136
  293. package/dist/pgToasts.js +0 -136
  294. package/dist/pgTooltip.js +0 -126
@@ -11,7 +11,7 @@ import template from './basic.html';
11
11
  template
12
12
  })
13
13
  export default class XPgGridBasic extends HTMLElement {
14
-
14
+ /*
15
15
  @Prop() fontId = 'D051337E-BC7E-11E5-A4E9-842B2B6CFE1B';
16
16
 
17
17
  @Part() $button0: HTMLButtonElement;
@@ -77,7 +77,8 @@ export default class XPgGridBasic extends HTMLElement {
77
77
  if (count === -1) {
78
78
  this.$grid.icons = this.icons;
79
79
  }
80
- this.$grid.icons = this.icons.slice(0, count);
80
+ // update array, fix later
81
+ this.$grid.icons.push(...this.icons.slice(0, count));
81
82
  }
82
83
 
83
84
  async handleSync(e: CustomEvent) {
package/pg/grid/grid.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Component, Prop, Part, Local } from '@pictogrammers/element';
2
- // import { createPopper } from '@popperjs/core';
3
2
  import { debounce, } from '../shared/debounce';
4
3
  import PgScroll from '../scroll/scroll';
5
4
 
package/pg/icon/README.md CHANGED
@@ -19,8 +19,9 @@ import PgIcon from '@pictogrammers/components/pg/icon';
19
19
 
20
20
  ## CSS Variables
21
21
 
22
- | CSS Variables | Default | Description |
23
- | ------------------- | --------- | ----------- |
24
- | `--pg-icon-color` | `#453C4F` | Color |
25
- | `--pg-icon-width` | `1.5rem` | Width |
26
- | `--pg-icon-height` | `1.5rem` | Height |
22
+ | CSS Variables | Default | Description |
23
+ | ------------------- | ----------- | ----------- |
24
+ | `--pg-icon-color` | `#453C4F` | Color |
25
+ | `--pg-icon-viewbox` | `0 0 24 24` | SVG viewBox |
26
+ | `--pg-icon-width` | `1.5rem` | Width |
27
+ | `--pg-icon-height` | `1.5rem` | Height |
@@ -11,6 +11,6 @@
11
11
  Set icon to Square
12
12
  </button>
13
13
 
14
- <div class="example">
15
- <pg-icon part="icon2" path="M12,4C14.21,4 16,5.79 16,8C16,10.21 14.21,12 12,12C9.79,12 8,10.21 8,8C8,5.79 9.79,4 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"></pg-icon>
14
+ <div class="example" style="--pg-icon-viewbox: 0 0 22 22">
15
+ <pg-icon part="icon2" path="M9 3H13V4H14V5H15V9H14V10H13V11H9V10H8V9H7V5H8V4H9V3M10 8V9H12V8H13V6H12V5H10V6H9V8H10M7 12H15V13H17V14H18V15H19V19H3V15H4V14H5V13H7V12M6 16H5V17H17V16H16V15H14V14H8V15H6V16Z"></pg-icon>
16
16
  </div>
@@ -21,7 +21,7 @@ export default class XPgIconBasic extends HTMLElement {
21
21
  }
22
22
 
23
23
  handleClear() {
24
- this.$icon1.path = '';
24
+ this.$icon1.path = 'M0 0h24v24H0V0zm2 2v20h20V2H2z';
25
25
  }
26
26
 
27
27
  handleAccount() {
package/pg/icon/icon.ts CHANGED
@@ -13,10 +13,16 @@ const noIcon = 'M0 0h24v24H0V0zm2 2v20h20V2H2z';
13
13
  export default class PgIcon extends HTMLElement {
14
14
  @Prop() path: string = noIcon;
15
15
 
16
+ @Part() $svg: SVGSVGElement;
16
17
  @Part() $path: SVGPathElement;
17
18
 
18
19
  render(changes) {
19
20
  if (changes.path) {
21
+ const viewBox = getComputedStyle(this).getPropertyValue('--pg-icon-viewbox');
22
+ this.$svg.setAttribute('viewBox', viewBox || '0 0 24 24');
23
+ if (!this.path) {
24
+ throw new Error('invalid path set on pg-icon');
25
+ }
20
26
  this.$path.setAttribute('d', this.path);
21
27
  }
22
28
  }
@@ -13,19 +13,19 @@ export default class XPgInputCheckListBasic extends HTMLElement {
13
13
  @Part() $value: HTMLSpanElement;
14
14
 
15
15
  connectedCallback() {
16
- this.$input.value = ['uuid1', 'uuid3'];
17
- this.$input.options = [
16
+ this.$input.value.push('uuid1', 'uuid3');
17
+ this.$input.options.push(
18
18
  { value: 'uuid1', label: 'Item 1' },
19
19
  { value: 'uuid2', label: 'Item 2' },
20
20
  { value: 'uuid3', label: 'Item 3', disabled: true },
21
21
  { value: 'uuid4', label: 'Item 4' }
22
- ];
23
- this.$value.innerText = this.$input.value.join(',');
22
+ );
23
+ this.$value.textContent = this.$input.value.join(',');
24
24
  this.$input.addEventListener('change', this.handleChange.bind(this));
25
25
  }
26
26
 
27
27
  handleChange(e) {
28
28
  const { value } = e.detail;
29
- this.$value.innerText = value.join(',');
29
+ this.$value.textContent = value.join(',');
30
30
  }
31
31
  }
@@ -52,6 +52,7 @@ export default class PgInputCheckList extends HTMLElement {
52
52
 
53
53
  render(changes) {
54
54
  if (changes.options) {
55
+ /*
55
56
  list(
56
57
  this.$list,
57
58
  this.options,
@@ -92,6 +93,7 @@ export default class PgInputCheckList extends HTMLElement {
92
93
  $item.querySelector('button').innerText = option.label;
93
94
  }
94
95
  );
96
+ */
95
97
  }
96
98
  if (changes.value) {
97
99
  //const value = [true, 'true'].includes(this.value);
@@ -42,10 +42,11 @@
42
42
  bottom: -1px;
43
43
  left: -1px;
44
44
  border-radius: 0.25rem;
45
- box-shadow: 0 0 0 3px var(--pg-search-focus-glow, rgb(79, 143, 249, 0.6));
45
+ box-shadow: 0 0 0 3px var(--pg-focus-color, rgb(79, 143, 249, 0.6));
46
46
  }
47
47
 
48
48
  [part="label"]:focus::before {
49
+ pointer-events: none;
49
50
  content: '';
50
51
  position: absolute;
51
52
  top: -1px;
@@ -53,7 +54,7 @@
53
54
  bottom: -1px;
54
55
  left: -1px;
55
56
  border-radius: 0.25rem;
56
- box-shadow: 0 0 0 3px var(--pg-search-focus-glow, rgb(79, 143, 249, 0.5));
57
+ box-shadow: 0 0 0 3px var(--pg-focus-color, rgb(79, 143, 249, 0.5));
57
58
  }
58
59
 
59
60
  [part="file"] {
@@ -0,0 +1,132 @@
1
+ # `<pg-input-pixel-editor>`
2
+
3
+ The `pg-input-pixel-editor` component is used to edit images. Tailored for pen or mouse input the editor can be used for various image editing tasks.
4
+
5
+ ```typescript
6
+ import '@pictogrammers/components/pgInputPixelEditor';
7
+ import { PgInputPixelEditor } from '@pictogrammers/components/pgInputPixelEditor';
8
+ ```
9
+
10
+ ```html
11
+ <pg-input-pixel-editor></pg-input-pixel-editor>
12
+ ```
13
+
14
+ ## Attributes
15
+
16
+ | Attributes | Tested | Description |
17
+ | ----------- | -------- | ----------- |
18
+ | `name` | | Unique name in `pg-form` |
19
+ | `width` | | Pixel width. Default `10` |
20
+ | `height` | | Pixel height. Default `10` |
21
+ | `size` | | Pixel size, minimum value `4`. Default `10` |
22
+ | `gridSize` | | Grid spacing between cells. Default `1` |
23
+
24
+ ## Events
25
+
26
+ | Events | Tested | Description |
27
+ | ---------- | -------- | ----------- |
28
+ | `change` | | `{ detail: { value }` |
29
+ | `input` | | `{ detail: { value }` |
30
+
31
+ ## Methods
32
+
33
+ See usage for each method below.
34
+
35
+ | Method | Tested | Description |
36
+ | ---------- | -------- | ----------- |
37
+ | `save(options)` | - | Save file. |
38
+ | `open(json)` | - | Open file. |
39
+ | `undo()` | - | Undo. |
40
+ | `hasUndo()` | - | Has undo |
41
+ | `hasRedo()` | - | Has redo |
42
+ | `redo()` | - | Redo. |
43
+ | `selectLayer()` | - | Select layer. |
44
+ | `getLayers()` | - | Get layer array. |
45
+ | `addLayer(option)` | - | Add layer. |
46
+ | `removeLayer(index)` | - | Remove layer. |
47
+ | `flattenLayers(layerIndexes)` | - | Flatten layers. |
48
+ | `moveLayer(startIndex, endIndex)` | - | Move layer. |
49
+ | `getColors()` | - | Get colors. |
50
+ | `addColor(r, g, b, a)` | - | Add color. |
51
+ | `removeColor(index)` | - | Remove color. |
52
+ | `moveColor(startIndex, endIndex)` | - | Move index. |
53
+ | `rotateClockwise()` | - | Rotate. |
54
+ | `rotateCounterclockwise()` | - | Rotate. |
55
+ | `move(x, y[, layer])` | - | Move. |
56
+ | `flipHorizontal()` | - | Flip horizontal. |
57
+ | `flipVertical()` | - | Flip vertical. |
58
+ | `invert()` | - | Invert layer. |
59
+
60
+ ### `save(options)` Method
61
+
62
+ The save method allows getting the JSON representation of the current editor.
63
+
64
+ ```typescript
65
+ @Part() $editor: PgInputPixelEditor;
66
+
67
+ handleSave() {
68
+ const json = await this.$editor.save({
69
+ // Include history
70
+ history: true,
71
+ });
72
+ // use json
73
+ }
74
+ ```
75
+
76
+ ### `open(json)` Method
77
+
78
+ The open method allows loading json for previously created images.
79
+
80
+ ```typescript
81
+ @Part() $editor: PgInputPixelEditor;
82
+
83
+ handleOpen() {
84
+ const error = await this.$editor.open(json);
85
+ if (error) {
86
+ throw new Error(error.message);
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## JSON Format
92
+
93
+ - `width` - Image width.
94
+ - `height` - Image width.
95
+ - `transparent` - Render transparent background.
96
+
97
+ A complete JSON storage for a 10x10 image.
98
+
99
+ ```json
100
+ {
101
+ "width": 10,
102
+ "height": 10,
103
+ "transparent": true,
104
+ "colors": [
105
+ [0, 0, 0, 0],
106
+ [0, 0, 0, 1]
107
+ ],
108
+ "layers": [
109
+ {
110
+ "name": "Layer 1",
111
+ "export": true,
112
+ "locked": false,
113
+ "visible": true,
114
+ "opacity": 1
115
+ }
116
+ ],
117
+ "data": [
118
+ [
119
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
120
+ [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
121
+ [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
122
+ [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
123
+ [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
124
+ [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
125
+ [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
126
+ [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
127
+ [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
128
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
129
+ ]
130
+ ]
131
+ }
132
+ ```
@@ -0,0 +1,29 @@
1
+ [part="debug"] {
2
+ background: #555;
3
+ padding: 1rem;
4
+ display: flex;
5
+ }
6
+
7
+ [part="debug"] canvas {
8
+ border: 1px solid #FFF;
9
+ }
10
+
11
+ [part="value1"] {
12
+ word-wrap: break-word;
13
+ }
14
+
15
+ .props {
16
+ display: flex;
17
+ flex-direction: row;
18
+ margin-bottom: 0.5rem;
19
+ }
20
+
21
+ label {
22
+ display: flex;
23
+ flex-direction: column;
24
+ }
25
+
26
+ h3 {
27
+ margin: 0.25rem 0;
28
+ font-size: 1.125rem;
29
+ }
@@ -0,0 +1,63 @@
1
+ <div class="example">
2
+ <div class="props">
3
+ <label>
4
+ Width
5
+ <input part="width" type="range" min="4" max="22">
6
+ </label>
7
+ <label>
8
+ Height
9
+ <input part="height" type="range" min="4" max="22">
10
+ </label>
11
+ <label>
12
+ Size
13
+ <input part="size" type="range" step="2" min="4" max="16">
14
+ </label>
15
+ <label>
16
+ <input part="transparent" type="checkbox">
17
+ Transparent
18
+ </label>
19
+ </div>
20
+ <pg-input-pixel-editor part="input" width="10" height="10" size="10" style="box-shadow:0 0 0.5rem rgba(0, 0, 0, 0.2)"></pg-input-pixel-editor>
21
+ <div>
22
+ <code>onchange: <span part="value1"></span></code>
23
+ </div>
24
+ <div>
25
+ <code>oninput: <span part="value2"></span></code>
26
+ </div>
27
+ <div>
28
+ <h3>Canvas Tools</h3>
29
+ <button part="reset">Reset</button>
30
+ <button part="clear">Clear</button>
31
+ <button part="invert">Invert</button>
32
+ |
33
+ <button part="save">Save</button>
34
+ <button part="open">Open</button>
35
+ </div>
36
+ <div>
37
+ <h3>Drawing Tools</h3>
38
+ <button part="modePixel">Pixel</button>
39
+ <button part="modeLine">Line</button>
40
+ <button part="modeRectangle">Rectangle</button>
41
+ <button part="modeRectangleOutline">Rectangle Outline</button>
42
+ <button part="modeEllipse">Ellipse</button>
43
+ <button part="modeEllipseOutline">Ellipse Outline</button>
44
+ </div>
45
+ <div>
46
+ <h3>Color Tools</h3>
47
+ <button part="addColor">Add Color</button>
48
+ <pre part="colors"></pre>
49
+ </div>
50
+ <div>
51
+ <h3>Layer Tools</h3>
52
+ <button part="addLayer">Add Layer</button>
53
+ <pre part="layers"></pre>
54
+ </div>
55
+ <div>
56
+ <h3>Example Tools</h3>
57
+ <input part="file" type="file" />
58
+ <button part="saveSvg">Save SVG</button>
59
+ <button part="savePng">Save Image</button>
60
+ </div>
61
+ <div part="debug"></div>
62
+ <pre part="output" contenteditable></pre>
63
+ </div>
@@ -0,0 +1,200 @@
1
+ import { Component, Part } from '@pictogrammers/element';
2
+ import PgInputPixelEditor from '../../inputPixelEditor';
3
+ import { maskToBitmap } from '../../utils/maskToBitmap';
4
+
5
+ import template from './basic.html';
6
+ import style from './basic.css';
7
+
8
+ @Component({
9
+ selector: 'x-pg-input-pixel-editor-basic',
10
+ style,
11
+ template
12
+ })
13
+ export default class XPgInputPixelEditorBasic extends HTMLElement {
14
+
15
+ @Part() $input: PgInputPixelEditor;
16
+ @Part() $value1: HTMLSpanElement;
17
+ @Part() $value2: HTMLSpanElement;
18
+ @Part() $debug: HTMLDivElement;
19
+ @Part() $width: HTMLInputElement;
20
+ @Part() $height: HTMLInputElement;
21
+ @Part() $size: HTMLInputElement;
22
+ @Part() $transparent: HTMLInputElement;
23
+
24
+ @Part() $reset: HTMLButtonElement;
25
+ @Part() $clear: HTMLButtonElement;
26
+ @Part() $invert: HTMLButtonElement;
27
+ @Part() $modePixel: HTMLButtonElement;
28
+ @Part() $modeLine: HTMLButtonElement;
29
+ @Part() $modeRectangle: HTMLButtonElement;
30
+ @Part() $modeRectangleOutline: HTMLButtonElement;
31
+ @Part() $modeEllipse: HTMLButtonElement;
32
+ @Part() $modeEllipseOutline: HTMLButtonElement;
33
+
34
+ @Part() $save: HTMLButtonElement;
35
+ @Part() $open: HTMLButtonElement;
36
+ @Part() $output: HTMLPreElement;
37
+ @Part() $file: HTMLInputElement;
38
+ @Part() $saveSvg: HTMLInputElement;
39
+ @Part() $savePng: HTMLInputElement;
40
+
41
+ // MAKE A LIST COMPONENT!!!! [text | delete]
42
+ @Part() $colors: HTMLPreElement;
43
+ @Part() $layers: HTMLPreElement;
44
+
45
+ connectedCallback() {
46
+ this.$width.value = '10';
47
+ this.$height.value = '10';
48
+ this.$size.value = '10';
49
+ this.$input.addEventListener('change', this.handleChange.bind(this));
50
+ this.$width.addEventListener('input', this.handleWidthChange.bind(this));
51
+ this.$height.addEventListener('input', this.handleHeightChange.bind(this));
52
+ this.$size.addEventListener('input', this.handleSizeChange.bind(this));
53
+ this.$transparent.addEventListener('input', this.handleTransparentChange.bind(this));
54
+ this.$input.addEventListener('input', this.handleInput.bind(this));
55
+ this.$input.addEventListener('debug', this.handleDebug.bind(this));
56
+ this.$modePixel.addEventListener('click', () => {
57
+ this.$input.inputModePixel();
58
+ });
59
+ this.$modeLine.addEventListener('click', () => {
60
+ this.$input.inputModeLine();
61
+ });
62
+ this.$modeRectangle.addEventListener('click', () => {
63
+ this.$input.inputModeRectangle();
64
+ });
65
+ this.$modeRectangleOutline.addEventListener('click', () => {
66
+ this.$input.inputModeRectangleOutline();
67
+ });
68
+ this.$modeEllipse.addEventListener('click', () => {
69
+ this.$input.inputModeEllipse();
70
+ });
71
+ this.$modeEllipseOutline.addEventListener('click', () => {
72
+ this.$input.inputModeEllipseOutline();
73
+ });
74
+ this.$reset.addEventListener('click', () => {
75
+ this.$input.reset();
76
+ });
77
+ this.$clear.addEventListener('click', () => {
78
+ this.$input.clear();
79
+ });
80
+ this.$invert.addEventListener('click', () => {
81
+ this.$input.invert();
82
+ });
83
+ this.$save.addEventListener('click', async () => {
84
+ const json = await this.$input.save();
85
+ this.$output.textContent = JSON.stringify(json, null, 4);
86
+ });
87
+ this.$open.addEventListener('click', () => {
88
+ const json = JSON.parse(this.$output.textContent || '');
89
+ this.$input.open(json as any);
90
+ });
91
+ this.$file.addEventListener('change', this.handleFile.bind(this));
92
+ this.$saveSvg.addEventListener('click', async () => {
93
+ try {
94
+ // @ts-ignore
95
+ const handle = await window.showSaveFilePicker({
96
+ suggestedName: 'Canvas',
97
+ types: [{
98
+ description: 'SVG Document',
99
+ accept: {'image/svg+xml': ['.svg']},
100
+ }],
101
+ });
102
+ const writable = await handle.createWritable();
103
+ await writable.write(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${this.$width.value} ${this.$height.value}">`);
104
+ await writable.write(`<path d="${'test'}" />`);
105
+ await writable.write('</svg>');
106
+ await writable.close();
107
+ } catch (e: any) {
108
+ // no save
109
+ }
110
+ });
111
+ this.$savePng.addEventListener('click', async () => {
112
+ try {
113
+ // @ts-ignore
114
+ const handle = await window.showSaveFilePicker({
115
+ suggestedName: 'CanvasName',
116
+ types: [{
117
+ description: 'SVG Document',
118
+ accept: {'image/svg+xml': ['.svg']},
119
+ }],
120
+ });
121
+ const writable = await handle.createWritable();
122
+ await writable.write('something');
123
+ await writable.write
124
+ await writable.close();
125
+ } catch (e: any) {
126
+ // no save
127
+ }
128
+ });
129
+ }
130
+
131
+ handleFile(e) {
132
+ const { files } = e.currentTarget;
133
+ if (files.length !== 1) {
134
+ throw new Error('select only 1 file');
135
+ }
136
+ switch(files[0].type) {
137
+ case 'image/svg+xml':
138
+ // Read the file
139
+ const reader = new FileReader();
140
+ reader.onload = () => {
141
+ const content = reader.result as string;
142
+ const size = content.match(/viewBox="\d+ \d+ (\d+) (\d+)"/) as string[];
143
+ const width = parseInt(size[1], 10);
144
+ const height = parseInt(size[2], 10);
145
+ const path = (content.match(/d="([^"]+)"/) as string[])[1];
146
+ // Render path
147
+ console.log(path, size[1], size[2]);
148
+ this.$input.applyTemplate(maskToBitmap(path, width, height));
149
+ ;
150
+ };
151
+ reader.onerror = () => {
152
+ throw new Error("Error reading the file. Please try again.");
153
+ };
154
+ reader.readAsText(files[0]);
155
+ break;
156
+ default:
157
+ throw new Error('Unsupported format.');
158
+ }
159
+ }
160
+
161
+ handleChange(e: CustomEvent) {
162
+ const { value } = e.detail;
163
+ this.$value1.textContent = value.join('--');
164
+ }
165
+
166
+ handleInput(e: CustomEvent) {
167
+ const { value } = e.detail;
168
+ this.$value2.textContent = value;
169
+ }
170
+
171
+ handleDebug(e: CustomEvent) {
172
+ const { x, y, width, height, context, baseLayer, editLayer, noEditLayer, previewLayer } = e.detail;
173
+ this.$debug.appendChild(baseLayer);
174
+ this.$debug.appendChild(editLayer);
175
+ this.$debug.appendChild(noEditLayer);
176
+ this.$debug.appendChild(previewLayer);
177
+ //context.strokeStyle = 'rgba(255, 0, 0, 0.3)';
178
+ //context.lineWidth = 1;
179
+ //context.strokeRect(x, y, width, height);
180
+ }
181
+
182
+ handleWidthChange(e) {
183
+ this.$input.width = e.target.value;
184
+ this.$debug.innerHTML = '';
185
+ }
186
+
187
+ handleHeightChange(e) {
188
+ this.$input.height = e.target.value;
189
+ this.$debug.innerHTML = '';
190
+ }
191
+
192
+ handleSizeChange(e) {
193
+ this.$input.size = e.target.value;
194
+ this.$debug.innerHTML = '';
195
+ }
196
+
197
+ handleTransparentChange(e) {
198
+ this.$input.transparent = e.target.checked;
199
+ }
200
+ }
@@ -0,0 +1,41 @@
1
+ function showOpenFilePickerPolyfill(options: any) {
2
+ return new Promise((resolve) => {
3
+ const input = document.createElement("input");
4
+ input.type = "file";
5
+ input.multiple = options.multiple;
6
+ input.accept = options.types
7
+ .map((type) => type.accept)
8
+ .flatMap((inst) => Object.keys(inst).flatMap((key) => inst[key]))
9
+ .join(",");
10
+
11
+ input.addEventListener("change", () => {
12
+ resolve(
13
+ [...(input.files as any)].map((file) => {
14
+ return {
15
+ getFile: async () =>
16
+ new Promise((resolve) => {
17
+ resolve(file);
18
+ }),
19
+ };
20
+ })
21
+ );
22
+ });
23
+
24
+ input.click();
25
+ });
26
+ }
27
+
28
+ /**
29
+ * Open file with polyfill for legacy browsers.
30
+ *
31
+ * @param options
32
+ * @returns
33
+ */
34
+ export function openFile(options) {
35
+ // @ts-ignore
36
+ if (window.showOpenFilePicker) {
37
+ // @ts-ignore
38
+ return window.showOpenFilePicker(options);
39
+ }
40
+ return showOpenFilePickerPolyfill(options);
41
+ }
@@ -0,0 +1,35 @@
1
+
2
+ /**
3
+ * Save file with polyfill for legacy browsers.
4
+ *
5
+ * @param blob File blob
6
+ * @returns Promise
7
+ */
8
+ export async function saveFile(blob) {
9
+ // @ts-ignore
10
+ if (window.showSaveFilePicker) {
11
+ const opts = {
12
+ types: [
13
+ {
14
+ description: "Text file",
15
+ accept: { "text/plain": [".txt"] },
16
+ },
17
+ ],
18
+ };
19
+ try {
20
+ // @ts-ignore
21
+ return await window.showSaveFilePicker(opts);
22
+ } catch (e) {
23
+ console.log('no save');
24
+ }
25
+ }
26
+ const downloadelem = document.createElement("a");
27
+ const url = URL.createObjectURL(blob);
28
+ document.body.appendChild(downloadelem);
29
+ downloadelem.href = url;
30
+ downloadelem.download = 'filename.txt';
31
+ downloadelem.click();
32
+ downloadelem.remove();
33
+ window.URL.revokeObjectURL(url);
34
+ return Promise.resolve();
35
+ }
@@ -0,0 +1,3 @@
1
+ import PgInputPixelEditor from './inputPixelEditor';
2
+
3
+ export default PgInputPixelEditor;
@@ -0,0 +1,27 @@
1
+ :host {
2
+ display: inline-flex;
3
+ }
4
+
5
+ [part="wrapper"] {
6
+ display: flex;
7
+ position: relative;
8
+ outline: 0;
9
+ }
10
+
11
+ [part="wrapper"]:focus-visible::before {
12
+ pointer-events: none;
13
+ content: '';
14
+ position: absolute;
15
+ top: -1px;
16
+ right: -1px;
17
+ bottom: -1px;
18
+ left: -1px;
19
+ border-radius: 0.125rem;
20
+ box-shadow: 0 0 0 3px var(--pg-focus-color, rgb(79, 143, 249, 0.5));
21
+ }
22
+
23
+ canvas {
24
+ touch-action: none;
25
+ user-select: none;
26
+ outline: 0;
27
+ }
@@ -0,0 +1,3 @@
1
+ <div part="wrapper" tabindex="0">
2
+ <canvas part="canvas" draggable="false"></canvas>
3
+ </div>