@threadlabs/looma 0.10.11 → 0.11.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 (128) hide show
  1. package/components/shared/editor.js +2 -26
  2. package/components/shared/icons.js +53 -0
  3. package/components/ui-avatar-group/ui-avatar-group.html +6 -6
  4. package/components/ui-avatar-group/ui-avatar-group.js +1 -1
  5. package/components/ui-breadcrumb-item/ui-breadcrumb-item.html +60 -0
  6. package/components/ui-breadcrumbs/ui-breadcrumbs.html +31 -0
  7. package/components/ui-card/ui-card.html +55 -0
  8. package/components/ui-combobox/ui-combobox.js +2 -2
  9. package/components/ui-context-menu/ui-context-menu.js +4 -4
  10. package/components/ui-cover/ui-cover.html +36 -0
  11. package/components/ui-description-item/ui-description-item.html +46 -0
  12. package/components/ui-description-list/ui-description-list.html +37 -0
  13. package/components/ui-icon/ui-icon.js +1 -1
  14. package/components/ui-list/ui-list.html +33 -0
  15. package/components/ui-list-item/ui-list-item.html +146 -0
  16. package/components/ui-menu/ui-menu.js +3 -3
  17. package/components/ui-page-header/ui-page-header.html +97 -0
  18. package/components/ui-radio/ui-radio.js +1 -1
  19. package/components/ui-radio-group/ui-radio-group.js +1 -1
  20. package/components/ui-section/ui-section.html +108 -0
  21. package/components/ui-spinner/ui-spinner.html +48 -0
  22. package/components/ui-status-message/ui-status-message.html +84 -0
  23. package/components/ui-text/ui-text.html +96 -0
  24. package/components/ui-tree/ui-tree.js +2 -2
  25. package/components/ui-tree-item/ui-tree-item.js +3 -3
  26. package/dist/index.js +1 -1
  27. package/editor/icons.d.ts +5 -0
  28. package/editor/index.js +6 -1
  29. package/package.json +1 -1
  30. package/styles/ui-avatar-group.css +6 -6
  31. package/styles/ui-breadcrumb-item.css +57 -0
  32. package/styles/ui-breadcrumbs.css +32 -0
  33. package/styles/ui-card.css +51 -0
  34. package/styles/ui-cover.css +35 -0
  35. package/styles/ui-description-item.css +43 -0
  36. package/styles/ui-description-list.css +38 -0
  37. package/styles/ui-list-item.css +146 -0
  38. package/styles/ui-list.css +33 -0
  39. package/styles/ui-page-header.css +89 -0
  40. package/styles/ui-section.css +94 -0
  41. package/styles/ui-spinner.css +42 -0
  42. package/styles/ui-status-message.css +72 -0
  43. package/styles/ui-text.css +85 -0
  44. package/vanilla/UiBreadcrumbItem.d.ts +14 -0
  45. package/vanilla/UiBreadcrumbItem.js +38 -0
  46. package/vanilla/UiBreadcrumbs.d.ts +14 -0
  47. package/vanilla/UiBreadcrumbs.js +39 -0
  48. package/vanilla/UiCard.d.ts +17 -0
  49. package/vanilla/UiCard.js +32 -0
  50. package/vanilla/UiCover.d.ts +14 -0
  51. package/vanilla/UiCover.js +28 -0
  52. package/vanilla/UiDescriptionItem.d.ts +14 -0
  53. package/vanilla/UiDescriptionItem.js +39 -0
  54. package/vanilla/UiDescriptionList.d.ts +14 -0
  55. package/vanilla/UiDescriptionList.js +28 -0
  56. package/vanilla/UiList.d.ts +14 -0
  57. package/vanilla/UiList.js +29 -0
  58. package/vanilla/UiListItem.d.ts +15 -0
  59. package/vanilla/UiListItem.js +77 -0
  60. package/vanilla/UiPageHeader.d.ts +14 -0
  61. package/vanilla/UiPageHeader.js +78 -0
  62. package/vanilla/UiSection.d.ts +16 -0
  63. package/vanilla/UiSection.js +64 -0
  64. package/vanilla/UiSpinner.d.ts +15 -0
  65. package/vanilla/UiSpinner.js +23 -0
  66. package/vanilla/UiStatusMessage.d.ts +16 -0
  67. package/vanilla/UiStatusMessage.js +53 -0
  68. package/vanilla/UiText.d.ts +20 -0
  69. package/vanilla/UiText.js +38 -0
  70. package/vanilla/index.js +13 -0
  71. package/vue/UiAvatarGroup.vue +6 -6
  72. package/vue/UiBreadcrumbItem.d.ts +18 -0
  73. package/vue/UiBreadcrumbItem.js +2 -0
  74. package/vue/UiBreadcrumbItem.vue +101 -0
  75. package/vue/UiBreadcrumbs.d.ts +18 -0
  76. package/vue/UiBreadcrumbs.js +2 -0
  77. package/vue/UiBreadcrumbs.vue +45 -0
  78. package/vue/UiCard.d.ts +24 -0
  79. package/vue/UiCard.js +2 -0
  80. package/vue/UiCard.vue +82 -0
  81. package/vue/UiCover.d.ts +18 -0
  82. package/vue/UiCover.js +2 -0
  83. package/vue/UiCover.vue +57 -0
  84. package/vue/UiDescriptionItem.d.ts +18 -0
  85. package/vue/UiDescriptionItem.js +2 -0
  86. package/vue/UiDescriptionItem.vue +58 -0
  87. package/vue/UiDescriptionList.d.ts +18 -0
  88. package/vue/UiDescriptionList.js +2 -0
  89. package/vue/UiDescriptionList.vue +62 -0
  90. package/vue/UiIconButton.d.ts +1 -1
  91. package/vue/UiList.d.ts +18 -0
  92. package/vue/UiList.js +2 -0
  93. package/vue/UiList.vue +60 -0
  94. package/vue/UiListItem.d.ts +26 -0
  95. package/vue/UiListItem.js +2 -0
  96. package/vue/UiListItem.vue +171 -0
  97. package/vue/UiPageHeader.d.ts +26 -0
  98. package/vue/UiPageHeader.js +2 -0
  99. package/vue/UiPageHeader.vue +118 -0
  100. package/vue/UiSection.d.ts +26 -0
  101. package/vue/UiSection.js +2 -0
  102. package/vue/UiSection.vue +128 -0
  103. package/vue/UiSpinner.d.ts +10 -0
  104. package/vue/UiSpinner.js +2 -0
  105. package/vue/UiSpinner.vue +87 -0
  106. package/vue/UiStatusMessage.d.ts +24 -0
  107. package/vue/UiStatusMessage.js +2 -0
  108. package/vue/UiStatusMessage.vue +121 -0
  109. package/vue/UiText.d.ts +30 -0
  110. package/vue/UiText.js +2 -0
  111. package/vue/UiText.vue +125 -0
  112. package/vue/chunks/UiAvatarGroup.js +1 -1
  113. package/vue/chunks/UiBreadcrumbItem.js +50 -0
  114. package/vue/chunks/UiBreadcrumbs.js +19 -0
  115. package/vue/chunks/UiCard.js +31 -0
  116. package/vue/chunks/UiCover.js +21 -0
  117. package/vue/chunks/UiDescriptionItem.js +16 -0
  118. package/vue/chunks/UiDescriptionList.js +21 -0
  119. package/vue/chunks/UiList.js +24 -0
  120. package/vue/chunks/UiListItem.js +39 -0
  121. package/vue/chunks/UiPageHeader.js +35 -0
  122. package/vue/chunks/UiSection.js +34 -0
  123. package/vue/chunks/UiSpinner.js +64 -0
  124. package/vue/chunks/UiStatusMessage.js +54 -0
  125. package/vue/chunks/UiText.js +40 -0
  126. package/vue/components.css +661 -29
  127. package/vue/index.d.ts +13 -0
  128. package/vue/index.js +15 -2
@@ -4,32 +4,8 @@ export const backgrounds = [
4
4
  ["background-green", "Green", "#dcfce7"], ["background-red", "Red", "#fee2e2"],
5
5
  ];
6
6
 
7
- // Serialized from Looma's framework-neutral icon catalog. Keeping the icon nodes here lets the
8
- // migration controllers stay directly importable in a browser without introducing a bundler-only
9
- // package resolution step.
10
- export const icons = {
11
- "align-left": [["path", { d: "M21 5H3" }], ["path", { d: "M15 12H3" }], ["path", { d: "M17 19H3" }]],
12
- "align-center": [["path", { d: "M21 5H3" }], ["path", { d: "M17 12H7" }], ["path", { d: "M19 19H5" }]],
13
- "align-right": [["path", { d: "M21 5H3" }], ["path", { d: "M21 12H9" }], ["path", { d: "M21 19H7" }]],
14
- rows: [["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }], ["path", { d: "M21 9H3" }], ["path", { d: "M21 15H3" }]],
15
- columns: [["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }], ["path", { d: "M9 3v18" }], ["path", { d: "M15 3v18" }]],
16
- table: [["path", { d: "M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18" }]],
17
- "chevron-down": [["path", { d: "m6 9 6 6 6-6" }]],
18
- "panel-top": [["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }], ["path", { d: "M3 9h18" }]],
19
- "panel-bottom": [["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }], ["path", { d: "M3 15h18" }]],
20
- "panel-left": [["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }], ["path", { d: "M9 3v18" }]],
21
- "panel-right": [["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }], ["path", { d: "M15 3v18" }]],
22
- eraser: [["path", { d: "M21 21H8a2 2 0 0 1-1.42-.587l-3.994-3.999a2 2 0 0 1 0-2.828l10-10a2 2 0 0 1 2.829 0l5.999 6a2 2 0 0 1 0 2.828L12.834 21" }], ["path", { d: "m5.082 11.09 8.828 8.828" }]],
23
- merge: [["path", { d: "m8 6 4-4 4 4" }], ["path", { d: "M12 2v10.3a4 4 0 0 1-1.172 2.872L4 22" }], ["path", { d: "m20 22-5-5" }]],
24
- split: [["path", { d: "M16 3h5v5" }], ["path", { d: "M8 3H3v5" }], ["path", { d: "M12 22v-8.3a4 4 0 0 0-1.172-2.872L3 3" }], ["path", { d: "m15 9 6-6" }]],
25
- trash: [["path", { d: "M10 11v6" }], ["path", { d: "M14 11v6" }], ["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }], ["path", { d: "M3 6h18" }], ["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }]],
26
- plus: [["path", { d: "M5 12h14" }], ["path", { d: "M12 5v14" }]],
27
- "grip-vertical": [["circle", { cx: "9", cy: "12", r: "1" }], ["circle", { cx: "9", cy: "5", r: "1" }], ["circle", { cx: "9", cy: "19", r: "1" }], ["circle", { cx: "15", cy: "12", r: "1" }], ["circle", { cx: "15", cy: "5", r: "1" }], ["circle", { cx: "15", cy: "19", r: "1" }]],
28
- "grip-horizontal": [["circle", { cx: "12", cy: "9", r: "1" }], ["circle", { cx: "19", cy: "9", r: "1" }], ["circle", { cx: "5", cy: "9", r: "1" }], ["circle", { cx: "12", cy: "15", r: "1" }], ["circle", { cx: "19", cy: "15", r: "1" }], ["circle", { cx: "5", cy: "15", r: "1" }]],
29
- "heading-1": [["path", { d: "M4 12h8" }], ["path", { d: "M4 18V6" }], ["path", { d: "M12 18V6" }], ["path", { d: "m17 12 3-2v8" }]],
30
- pilcrow: [["path", { d: "M13 4v16" }], ["path", { d: "M17 4v16" }], ["path", { d: "M19 4H9.5a4.5 4.5 0 0 0 0 9H13" }]],
31
- quote: [["path", { d: "M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z" }], ["path", { d: "M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z" }]],
32
- };
7
+ // Looma's icon set as plain data, generated from LOOMA_ICONS (see shared/icons.js).
8
+ export { icons } from "./icons.js";
33
9
 
34
10
  export function normalizeAnchor(value) {
35
11
  if (!value || typeof value !== "object") return null;
@@ -0,0 +1,53 @@
1
+ // Generated by tools/scripts/generate-icon-catalog.mjs from LOOMA_ICONS. Do not edit.
2
+ export const icons = {
3
+ "align-center": [["path",{"d":"M21 5H3"}],["path",{"d":"M17 12H7"}],["path",{"d":"M19 19H5"}]],
4
+ "align-left": [["path",{"d":"M21 5H3"}],["path",{"d":"M15 12H3"}],["path",{"d":"M17 19H3"}]],
5
+ "align-right": [["path",{"d":"M21 5H3"}],["path",{"d":"M21 12H9"}],["path",{"d":"M21 19H7"}]],
6
+ "arrow-left": [["path",{"d":"m12 19-7-7 7-7"}],["path",{"d":"M19 12H5"}]],
7
+ "bold": [["path",{"d":"M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8"}]],
8
+ "braces": [["path",{"d":"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1"}],["path",{"d":"M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1"}]],
9
+ "chevron-down": [["path",{"d":"m6 9 6 6 6-6"}]],
10
+ "chevron-left": [["path",{"d":"m15 18-6-6 6-6"}]],
11
+ "chevron-right": [["path",{"d":"m9 18 6-6-6-6"}]],
12
+ "circle-check": [["circle",{"cx":"12","cy":"12","r":"10"}],["path",{"d":"m9 12 2 2 4-4"}]],
13
+ "circle-x": [["circle",{"cx":"12","cy":"12","r":"10"}],["path",{"d":"m15 9-6 6"}],["path",{"d":"m9 9 6 6"}]],
14
+ "code-xml": [["path",{"d":"m18 16 4-4-4-4"}],["path",{"d":"m6 8-4 4 4 4"}],["path",{"d":"m14.5 4-5 16"}]],
15
+ "columns": [["rect",{"width":"18","height":"18","x":"3","y":"3","rx":"2"}],["path",{"d":"M9 3v18"}],["path",{"d":"M15 3v18"}]],
16
+ "ellipsis": [["circle",{"cx":"12","cy":"12","r":"1"}],["circle",{"cx":"19","cy":"12","r":"1"}],["circle",{"cx":"5","cy":"12","r":"1"}]],
17
+ "eraser": [["path",{"d":"M21 21H8a2 2 0 0 1-1.42-.587l-3.994-3.999a2 2 0 0 1 0-2.828l10-10a2 2 0 0 1 2.829 0l5.999 6a2 2 0 0 1 0 2.828L12.834 21"}],["path",{"d":"m5.082 11.09 8.828 8.828"}]],
18
+ "file-text": [["path",{"d":"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"}],["path",{"d":"M14 2v5a1 1 0 0 0 1 1h5"}],["path",{"d":"M10 9H8"}],["path",{"d":"M16 13H8"}],["path",{"d":"M16 17H8"}]],
19
+ "folder": [["path",{"d":"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"}]],
20
+ "grip-horizontal": [["circle",{"cx":"12","cy":"9","r":"1"}],["circle",{"cx":"19","cy":"9","r":"1"}],["circle",{"cx":"5","cy":"9","r":"1"}],["circle",{"cx":"12","cy":"15","r":"1"}],["circle",{"cx":"19","cy":"15","r":"1"}],["circle",{"cx":"5","cy":"15","r":"1"}]],
21
+ "grip-vertical": [["circle",{"cx":"9","cy":"12","r":"1"}],["circle",{"cx":"9","cy":"5","r":"1"}],["circle",{"cx":"9","cy":"19","r":"1"}],["circle",{"cx":"15","cy":"12","r":"1"}],["circle",{"cx":"15","cy":"5","r":"1"}],["circle",{"cx":"15","cy":"19","r":"1"}]],
22
+ "heading-1": [["path",{"d":"M4 12h8"}],["path",{"d":"M4 18V6"}],["path",{"d":"M12 18V6"}],["path",{"d":"m17 12 3-2v8"}]],
23
+ "heading-2": [["path",{"d":"M4 12h8"}],["path",{"d":"M4 18V6"}],["path",{"d":"M12 18V6"}],["path",{"d":"M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1"}]],
24
+ "heading-3": [["path",{"d":"M4 12h8"}],["path",{"d":"M4 18V6"}],["path",{"d":"M12 18V6"}],["path",{"d":"M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2"}],["path",{"d":"M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2"}]],
25
+ "highlighter": [["path",{"d":"m9 11-6 6v3h9l3-3"}],["path",{"d":"m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4"}]],
26
+ "image": [["rect",{"width":"18","height":"18","x":"3","y":"3","rx":"2","ry":"2"}],["circle",{"cx":"9","cy":"9","r":"2"}],["path",{"d":"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"}]],
27
+ "info": [["circle",{"cx":"12","cy":"12","r":"10"}],["path",{"d":"M12 16v-4"}],["path",{"d":"M12 8h.01"}]],
28
+ "italic": [["line",{"x1":"19","x2":"10","y1":"4","y2":"4"}],["line",{"x1":"14","x2":"5","y1":"20","y2":"20"}],["line",{"x1":"15","x2":"9","y1":"4","y2":"20"}]],
29
+ "list": [["path",{"d":"M3 5h.01"}],["path",{"d":"M3 12h.01"}],["path",{"d":"M3 19h.01"}],["path",{"d":"M8 5h13"}],["path",{"d":"M8 12h13"}],["path",{"d":"M8 19h13"}]],
30
+ "list-ordered": [["path",{"d":"M11 5h10"}],["path",{"d":"M11 12h10"}],["path",{"d":"M11 19h10"}],["path",{"d":"M4 4h1v5"}],["path",{"d":"M4 9h2"}],["path",{"d":"M6.5 20H3.4c0-1 2.6-1.925 2.6-3.5a1.5 1.5 0 0 0-2.6-1.02"}]],
31
+ "list-todo": [["path",{"d":"M13 5h8"}],["path",{"d":"M13 12h8"}],["path",{"d":"M13 19h8"}],["path",{"d":"m3 17 2 2 4-4"}],["rect",{"x":"3","y":"4","width":"6","height":"6","rx":"1"}]],
32
+ "loader": [["path",{"d":"M21 12a9 9 0 1 1-6.219-8.56"}]],
33
+ "merge": [["path",{"d":"m8 6 4-4 4 4"}],["path",{"d":"M12 2v10.3a4 4 0 0 1-1.172 2.872L4 22"}],["path",{"d":"m20 22-5-5"}]],
34
+ "minus": [["path",{"d":"M5 12h14"}]],
35
+ "notebook-pen": [["path",{"d":"M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4"}],["path",{"d":"M2 6h4"}],["path",{"d":"M2 10h4"}],["path",{"d":"M2 14h4"}],["path",{"d":"M2 18h4"}],["path",{"d":"M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z"}]],
36
+ "paint-bucket": [["path",{"d":"m19 11-8-8-8.6 8.6a2 2 0 0 0 0 2.8l5.2 5.2c.8.8 2 .8 2.8 0L19 11Z"}],["path",{"d":"m5 2 5 5"}],["path",{"d":"M2 13h15"}],["path",{"d":"M22 20a2 2 0 1 1-4 0c0-1.6 1.7-2.4 2-4 .3 1.6 2 2.4 2 4Z"}]],
37
+ "panel-bottom": [["rect",{"width":"18","height":"18","x":"3","y":"3","rx":"2"}],["path",{"d":"M3 15h18"}]],
38
+ "panel-left": [["rect",{"width":"18","height":"18","x":"3","y":"3","rx":"2"}],["path",{"d":"M9 3v18"}]],
39
+ "panel-right": [["rect",{"width":"18","height":"18","x":"3","y":"3","rx":"2"}],["path",{"d":"M15 3v18"}]],
40
+ "panel-top": [["rect",{"width":"18","height":"18","x":"3","y":"3","rx":"2"}],["path",{"d":"M3 9h18"}]],
41
+ "pilcrow": [["path",{"d":"M13 4v16"}],["path",{"d":"M17 4v16"}],["path",{"d":"M19 4H9.5a4.5 4.5 0 0 0 0 9H13"}]],
42
+ "plus": [["path",{"d":"M5 12h14"}],["path",{"d":"M12 5v14"}]],
43
+ "quote": [["path",{"d":"M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z"}],["path",{"d":"M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z"}]],
44
+ "redo": [["path",{"d":"m15 14 5-5-5-5"}],["path",{"d":"M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13"}]],
45
+ "rows": [["rect",{"width":"18","height":"18","x":"3","y":"3","rx":"2"}],["path",{"d":"M21 9H3"}],["path",{"d":"M21 15H3"}]],
46
+ "split": [["path",{"d":"M16 3h5v5"}],["path",{"d":"M8 3H3v5"}],["path",{"d":"M12 22v-8.3a4 4 0 0 0-1.172-2.872L3 3"}],["path",{"d":"m15 9 6-6"}]],
47
+ "strikethrough": [["path",{"d":"M16 4H9a3 3 0 0 0-2.83 4"}],["path",{"d":"M14 12a4 4 0 0 1 0 8H6"}],["line",{"x1":"4","x2":"20","y1":"12","y2":"12"}]],
48
+ "table": [["path",{"d":"M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18"}]],
49
+ "trash": [["path",{"d":"M10 11v6"}],["path",{"d":"M14 11v6"}],["path",{"d":"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"}],["path",{"d":"M3 6h18"}],["path",{"d":"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"}]],
50
+ "triangle-alert": [["path",{"d":"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"}],["path",{"d":"M12 9v4"}],["path",{"d":"M12 17h.01"}]],
51
+ "underline": [["path",{"d":"M6 4v6a6 6 0 0 0 12 0V4"}],["line",{"x1":"4","x2":"20","y1":"20","y2":"20"}]],
52
+ "undo": [["path",{"d":"M9 14 4 9l5-5"}],["path",{"d":"M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11"}]],
53
+ };
@@ -15,10 +15,10 @@
15
15
  </div>
16
16
  <style>
17
17
  :host {
18
- /* Avatars separate with a tight, crisp edge, matching Looma's 1px borders rather than the
19
- * diffuse elevation overlays use. */
20
- --_overlap-shadow: -2px 0 2px -1px rgba(0, 0, 0, 0.22);
21
- --_edge-ring: 0 0 0 1px rgba(0, 0, 0, 0.08);
18
+ /* Each avatar is ringed in the surface colour, so where one overlaps the next it reads as a
19
+ * whole circle set on top, not a shape cut into the one beneath. */
20
+ --_overlap-shadow: 0 0 0 0 transparent;
21
+ --_edge-ring: 0 0 0 2px var(--ui-surface);
22
22
 
23
23
  display: flex;
24
24
  align-items: center;
@@ -29,7 +29,7 @@
29
29
  /* Overlap and the separating shadow are applied by the controller: slotted avatars are nested
30
30
  * component roots outside this style scope. */
31
31
  :slotted(*) {
32
- margin-inline-start: -0.625rem;
32
+ margin-inline-start: -0.5rem;
33
33
  flex-shrink: 0;
34
34
  border-radius: 999px;
35
35
  }
@@ -39,7 +39,7 @@
39
39
  }
40
40
 
41
41
  .overflow {
42
- margin-inline-start: -0.625rem;
42
+ margin-inline-start: -0.5rem;
43
43
  display: inline-flex;
44
44
  align-items: center;
45
45
  justify-content: center;
@@ -8,7 +8,7 @@ export default function controller(host) {
8
8
  const avatars = Array.from(element.children).filter((child) => child !== host.refs.overflow);
9
9
  avatars.forEach((avatar, index) => {
10
10
  avatar.style.display = index >= visible ? "none" : "";
11
- avatar.style.marginInlineStart = index === 0 ? "0px" : "-0.625rem";
11
+ avatar.style.marginInlineStart = index === 0 ? "0px" : "-0.5rem";
12
12
  avatar.style.borderRadius = "999px";
13
13
  // Later avatars cast a crisp shadow back onto the one they overlap; the first overlaps nothing.
14
14
  avatar.style.boxShadow = index === 0
@@ -0,0 +1,60 @@
1
+ <template component="ui-breadcrumb-item">
2
+ <defs>
3
+ <prop name="current" type="boolean" default="false"
4
+ >Marks the step as the view you are on: it is plain text with aria-current="page". Every other step holds a link.</prop>
5
+ </defs>
6
+ <li :aria-current="{ true: 'page', false: null }[format('%s', current)]">
7
+ <span class="separator" aria-hidden="true"><ui-icon name="chevron-right"></ui-icon></span>
8
+ <span class="content"><slot></slot></span>
9
+ </li>
10
+ <style>
11
+ /* One step in a ui-breadcrumbs trail: a link up to that place, or the current view. A chevron leads
12
+ every step but the first. An icon slotted before the name sits with it. */
13
+ :host {
14
+ display: inline-flex;
15
+ align-items: center;
16
+ gap: var(--ui-space-2);
17
+ min-inline-size: 0;
18
+ }
19
+
20
+ .separator {
21
+ display: inline-flex;
22
+ color: var(--ui-text-muted);
23
+ font-size: var(--ui-font-size-xs);
24
+ }
25
+
26
+ :host:first-child .separator {
27
+ display: none;
28
+ }
29
+
30
+ .content {
31
+ display: inline-flex;
32
+ align-items: center;
33
+ gap: var(--ui-space-1);
34
+ min-inline-size: 0;
35
+ }
36
+
37
+ .content > :slotted(a) {
38
+ display: inline-flex;
39
+ align-items: center;
40
+ gap: var(--ui-space-1);
41
+ color: var(--ui-text-secondary);
42
+ text-decoration: none;
43
+ }
44
+
45
+ .content > :slotted(a:hover) {
46
+ color: var(--ui-text-primary);
47
+ text-decoration: underline;
48
+ }
49
+
50
+ :host-state([current]) .content {
51
+ color: var(--ui-text-primary);
52
+ font-weight: var(--ui-font-medium);
53
+ }
54
+
55
+ /* A component that sets its display still honours the hidden attribute on its root. */
56
+ :host[hidden] {
57
+ display: none;
58
+ }
59
+ </style>
60
+ </template>
@@ -0,0 +1,31 @@
1
+ <template component="ui-breadcrumbs">
2
+ <defs>
3
+ <prop name="label" type="string" default="Breadcrumb">The navigation landmark's accessible name.</prop>
4
+ </defs>
5
+ <nav :aria-label="label"><ol role="list"><slot></slot></ol></nav>
6
+ <style>
7
+ /* Where a view sits: a trail of ui-breadcrumb-item, from the top down to the current view. It wraps
8
+ rather than scrolls, so every step stays reachable. */
9
+ :host {
10
+ display: block;
11
+ min-inline-size: 0;
12
+ color: var(--ui-text-muted);
13
+ font-size: var(--ui-font-size-sm);
14
+ }
15
+
16
+ ol {
17
+ display: flex;
18
+ flex-wrap: wrap;
19
+ align-items: center;
20
+ gap: var(--ui-space-1) var(--ui-space-2);
21
+ margin: 0;
22
+ padding: 0;
23
+ list-style: none;
24
+ }
25
+
26
+ /* A component that sets its display still honours the hidden attribute on its root. */
27
+ :host[hidden] {
28
+ display: none;
29
+ }
30
+ </style>
31
+ </template>
@@ -0,0 +1,55 @@
1
+ <template component="ui-card">
2
+ <defs>
3
+ <prop name="variant" type="outlined | subtle | elevated" default="outlined"
4
+ >The surface. outlined is a bordered panel on the page; subtle is a quiet filled one with no border, for supporting details set apart from the flow;
5
+ elevated floats above the page with a shadow, for a view's one card, such as sign-in.</prop>
6
+ <prop name="padding" type="sm | md | lg" default="md"
7
+ >The space inside the card: sm is snug (0.75rem), md is the default (1.5rem), and lg is roomy (2rem).</prop>
8
+ <prop name="tone" type="neutral | danger" default="neutral">danger draws an outlined card's border in the danger colour.</prop>
9
+ </defs>
10
+ <div as="div|section|article|aside"><slot></slot></div>
11
+ <style>
12
+ /* A surface that groups content. Its children stack with even space between them, so a card
13
+ needs no layout of its own. */
14
+ :host {
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: var(--ui-space-4);
18
+ box-sizing: border-box;
19
+ min-inline-size: 0;
20
+ padding: var(--ui-space-5);
21
+ border: 1px solid var(--ui-border-default);
22
+ border-radius: var(--ui-radius-lg);
23
+ background: var(--ui-surface-raised);
24
+ color: var(--ui-text-primary);
25
+ }
26
+
27
+ :host-state([padding="sm"]) {
28
+ gap: var(--ui-space-2);
29
+ padding: var(--ui-space-3);
30
+ }
31
+
32
+ :host-state([padding="lg"]) {
33
+ padding: var(--ui-space-6);
34
+ }
35
+
36
+ :host-state([variant="subtle"]) {
37
+ border-color: transparent;
38
+ background: var(--ui-surface-muted);
39
+ }
40
+
41
+ :host-state([variant="elevated"]) {
42
+ border-color: var(--ui-border-subtle);
43
+ box-shadow: var(--ui-shadow-lg);
44
+ }
45
+
46
+ :host-state([tone="danger"]) {
47
+ border-color: var(--ui-danger);
48
+ }
49
+
50
+ /* A component that sets its display still honours the hidden attribute on its root. */
51
+ :host[hidden] {
52
+ display: none;
53
+ }
54
+ </style>
55
+ </template>
@@ -415,8 +415,8 @@ export default function controller(host) {
415
415
  };
416
416
  const onCompositionstart = (event) => { if (event.target === input) composing = true; };
417
417
  const onCompositionend = (event) => { if (event.target === input) { composing = false; onInput(new InputEvent("input")); } };
418
- const onTooltipOpen = (event) => { if (event.target.closest?.('[data-component~="ui-tooltip"]')) host.state.helpOpen = true; };
419
- const onTooltipClose = (event) => { if (event.target.closest?.('[data-component~="ui-tooltip"]')) host.state.helpOpen = false; };
418
+ const onTooltipOpen = (event) => { if (event.target.closest?.('[role="tooltip"]')) host.state.helpOpen = true; };
419
+ const onTooltipClose = (event) => { if (event.target.closest?.('[role="tooltip"]')) host.state.helpOpen = false; };
420
420
 
421
421
  // The selection the props describe: where the combobox starts, and where a form reset returns it.
422
422
  const applyDefaults = () => {
@@ -17,7 +17,7 @@ export default function controller(host) {
17
17
  let lastOpenProp = Boolean(host.state.open);
18
18
  host.state.internalOpen = lastOpenProp;
19
19
 
20
- const items = () => Array.from(element.querySelectorAll('[data-component~="ui-menu-item"]')).filter((item) => !disabled(item));
20
+ const items = () => Array.from(element.querySelectorAll('[role="menuitem"]')).filter((item) => !disabled(item));
21
21
  const focusFirst = () => requestAnimationFrame(() => items()[0]?.focus());
22
22
  const targetEvents = { contextmenu: onContextMenu, keydown: onTargetKeydown, pointerdown: onPointerdown, pointerup: endPress, pointercancel: endPress };
23
23
  const detach = () => {
@@ -107,7 +107,7 @@ export default function controller(host) {
107
107
  event.preventDefault();
108
108
  requestTopOverlayClose(document, "escape", "keyboard");
109
109
  } else if (["Enter", " "].includes(event.key)) {
110
- const item = event.target.closest?.('[data-component~="ui-menu-item"]');
110
+ const item = event.target.closest?.('[role="menuitem"]');
111
111
  if (!item || disabled(item)) return;
112
112
  event.preventDefault();
113
113
  host.dispatch("select", { value: item.getAttribute("data-value") ?? item.getAttribute("value") ?? "", trigger: "keyboard" });
@@ -116,7 +116,7 @@ export default function controller(host) {
116
116
  const enabled = items();
117
117
  if (!enabled.length) return;
118
118
  event.preventDefault();
119
- const index = enabled.indexOf(event.target.closest?.('[data-component~="ui-menu-item"]'));
119
+ const index = enabled.indexOf(event.target.closest?.('[role="menuitem"]'));
120
120
  const next = event.key === "ArrowDown"
121
121
  ? (index < 0 ? 0 : Math.min(index + 1, enabled.length - 1))
122
122
  : (index <= 0 ? enabled.length - 1 : index - 1);
@@ -124,7 +124,7 @@ export default function controller(host) {
124
124
  }
125
125
  };
126
126
  const onClick = (event) => {
127
- const item = event.target.closest?.('[data-component~="ui-menu-item"]');
127
+ const item = event.target.closest?.('[role="menuitem"]');
128
128
  if (!item || disabled(item)) return;
129
129
  host.dispatch("select", { value: item.getAttribute("data-value") ?? item.getAttribute("value") ?? "", trigger: "pointer" });
130
130
  close("action", "pointer");
@@ -0,0 +1,36 @@
1
+ <template component="ui-cover">
2
+ <defs>
3
+ <prop name="size" type="screen | fill" default="screen"
4
+ >How tall the cover is. screen is at least the viewport's height, for a view that is one centred card, such as sign-in; fill takes the space its parent
5
+ gives it.</prop>
6
+ </defs>
7
+ <div><slot></slot></div>
8
+ <style>
9
+ /* A layout primitive that centres its content in the space, both ways, with room around it: the
10
+ frame for a view that is one card or one message. */
11
+ :host {
12
+ display: flex;
13
+ flex-direction: column;
14
+ align-items: center;
15
+ justify-content: center;
16
+ gap: var(--ui-space-6);
17
+ box-sizing: border-box;
18
+ min-block-size: 100dvh;
19
+ padding: var(--ui-space-6) var(--ui-space-4);
20
+ }
21
+
22
+ :host-state([size="fill"]) {
23
+ flex: 1;
24
+ min-block-size: 100%;
25
+ }
26
+
27
+ :host > :slotted(*) {
28
+ max-inline-size: 100%;
29
+ }
30
+
31
+ /* A component that sets its display still honours the hidden attribute on its root. */
32
+ :host[hidden] {
33
+ display: none;
34
+ }
35
+ </style>
36
+ </template>
@@ -0,0 +1,46 @@
1
+ <template component="ui-description-item">
2
+ <defs>
3
+ <prop name="term" type="string" default="">What the value is, such as "Invited by". The value is the item's content.</prop>
4
+ </defs>
5
+ <div>
6
+ <dt><template $value="term"></template></dt>
7
+ <dd><slot></slot></dd>
8
+ </div>
9
+ <style>
10
+ /* One term and its value in a ui-description-list, laid out by the list's layout. */
11
+ :host {
12
+ display: var(--_ui-description-display, grid);
13
+ grid-column: var(--_ui-description-column, 1 / -1);
14
+ grid-template-columns: subgrid;
15
+ flex-direction: column;
16
+ align-items: var(--_ui-description-align, baseline);
17
+ gap: var(--ui-space-1) var(--ui-space-6);
18
+ min-inline-size: 0;
19
+ padding: var(--_ui-description-padding, 0);
20
+ border-width: var(--_ui-description-border-width, 0);
21
+ border-style: solid;
22
+ border-color: var(--ui-border-default);
23
+ border-radius: var(--ui-radius-md);
24
+ font-size: var(--ui-font-size-sm);
25
+ }
26
+
27
+ dt {
28
+ color: var(--ui-text-muted);
29
+ }
30
+
31
+ dd {
32
+ margin: 0;
33
+ min-inline-size: 0;
34
+ color: var(--ui-text-primary);
35
+ font-weight: var(--ui-font-medium);
36
+ font-size: var(--_ui-description-value-size, inherit);
37
+ text-align: start;
38
+ overflow-wrap: anywhere;
39
+ }
40
+
41
+ /* A component that sets its display still honours the hidden attribute on its root. */
42
+ :host[hidden] {
43
+ display: none;
44
+ }
45
+ </style>
46
+ </template>
@@ -0,0 +1,37 @@
1
+ <template component="ui-description-list">
2
+ <defs>
3
+ <prop name="layout" type="rows | tiles" default="rows"
4
+ >rows sets each term beside its value, one per line, for a short summary; tiles sets each pair on its own bordered tile in a grid, term above value, for
5
+ figures and facts to scan.</prop>
6
+ </defs>
7
+ <dl><slot></slot></dl>
8
+ <style>
9
+ /* Named values: a term and what it is, for each item (ui-description-item). */
10
+ /* Rows line every term up in one column and every value in the next, through subgrid. */
11
+ :host {
12
+ display: grid;
13
+ grid-template-columns: minmax(6rem, max-content) minmax(0, 1fr);
14
+ gap: var(--ui-space-2) var(--ui-space-6);
15
+ min-inline-size: 0;
16
+ margin: 0;
17
+ }
18
+
19
+ /* Tiles pass their shape to the items through private properties, which cross into each item. */
20
+ :host-state([layout="tiles"]) {
21
+ --_ui-description-display: flex;
22
+ --_ui-description-column: auto;
23
+ --_ui-description-align: flex-start;
24
+ --_ui-description-value-size: var(--ui-font-size-lg);
25
+ --_ui-description-padding: var(--ui-space-3);
26
+ --_ui-description-border-width: 1px;
27
+ display: grid;
28
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, 10rem), 1fr));
29
+ gap: var(--ui-space-3);
30
+ }
31
+
32
+ /* A component that sets its display still honours the hidden attribute on its root. */
33
+ :host[hidden] {
34
+ display: none;
35
+ }
36
+ </style>
37
+ </template>
@@ -1,4 +1,4 @@
1
- import { icons } from "../shared/editor.js";
1
+ import { icons } from "../shared/icons.js";
2
2
 
3
3
  // The icon's shapes, from Looma's icon set, for the template to draw.
4
4
  export default function controller(host) {
@@ -0,0 +1,33 @@
1
+ <template component="ui-list">
2
+ <defs>
3
+ <prop name="layout" type="rows | grid" default="rows"
4
+ >How the items are laid out. Rows stack the items one per line, for a list read top to bottom. Grid sets them in as many columns as fit, each at least
5
+ --ui-list-min-item-width (14rem) wide, for card items such as pinned or featured entries.</prop>
6
+ </defs>
7
+ <ul role="list"><slot></slot></ul>
8
+ <style>
9
+ /* A list of items (ui-list-item). It owns the spacing between them, so a view never sets it. The
10
+ explicit list role keeps the list announced as one: some browsers drop it from a list with no
11
+ markers. */
12
+ :host {
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: var(--ui-list-gap, var(--ui-space-1));
16
+ min-inline-size: 0;
17
+ margin: 0;
18
+ padding: 0;
19
+ list-style: none;
20
+ }
21
+
22
+ :host-state([layout="grid"]) {
23
+ display: grid;
24
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--ui-list-min-item-width, 14rem)), 1fr));
25
+ gap: var(--ui-list-gap, var(--ui-space-3));
26
+ }
27
+
28
+ /* A component that sets its display still honours the hidden attribute on its root. */
29
+ :host[hidden] {
30
+ display: none;
31
+ }
32
+ </style>
33
+ </template>