@threadlabs/looma 0.11.2 → 0.11.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.11.2",
3
+ "version": "0.11.4",
4
4
  "type": "module",
5
5
  "description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
6
6
  "license": "MIT",
@@ -64,6 +64,8 @@
64
64
  --_callout-icon: var(--ui-danger-solid);
65
65
  }
66
66
 
67
+ /* A link in the callout's text is underlined, so it reads as a link by more than colour. */
68
+
67
69
  /* A component that sets its display still honours the hidden attribute on its root. */
68
70
  :scope[hidden] {
69
71
  display: none;
@@ -72,5 +74,13 @@
72
74
  @scope ([data-component~="ui-callout"]) to ([data-component]) {
73
75
  /* One line box tall, so the icon centres on the first line of text. */
74
76
 
77
+ /* A link in the callout's text is underlined, so it reads as a link by more than colour. */
78
+ .content :where([data-slotted], [data-slotted] *):is(a) {
79
+ color: var(--ui-accent-active);
80
+ text-decoration: underline;
81
+ text-decoration-thickness: 0.06em;
82
+ text-underline-offset: 0.18em;
83
+ }
84
+
75
85
  /* A component that sets its display still honours the hidden attribute on its root. */
76
86
  }
@@ -27,6 +27,8 @@
27
27
  line-height: var(--ui-line-height-md);
28
28
  }
29
29
 
30
+ /* An error reads in the danger colour, the one the invalid control's border takes. */
31
+
30
32
  /* A component that sets its display still honours the hidden attribute on its root. */
31
33
  :scope[hidden] {
32
34
  display: none;
@@ -40,9 +42,10 @@
40
42
  min-block-size: var(--ui-form-field-help-min-block-size, 0);
41
43
  }
42
44
 
45
+ /* An error reads in the danger colour, the one the invalid control's border takes. */
43
46
  .error,
44
47
  :where([data-slotted], [data-slotted] *):is([role="alert"]) {
45
- color: var(--ui-accent-active);
48
+ color: var(--ui-danger);
46
49
  font-size: var(--ui-font-size-sm);
47
50
  }
48
51
 
@@ -10,6 +10,8 @@
10
10
  --ui-input-border: transparent;
11
11
  --ui-input-border-hover: transparent;
12
12
  --ui-input-focus-border: transparent;
13
+ --ui-input-invalid-border: transparent;
14
+ --ui-input-invalid-focus-shadow: none;
13
15
  --ui-input-shadow: none;
14
16
  --ui-input-focus-shadow: none;
15
17
  --ui-input-radius: 0;
@@ -46,13 +46,15 @@
46
46
  /* The app's invalid flag, or the browser's own verdict once the user has left an invalid field. */
47
47
  :scope[aria-invalid="true"],
48
48
  :scope:is(:user-invalid, [data-user-invalid]) {
49
- border-color: var(--ui-danger-solid);
49
+ border-color: var(--ui-input-invalid-border, var(--ui-danger-solid));
50
50
  }
51
51
 
52
52
  :scope:is([aria-invalid="true"], :is(:user-invalid, [data-user-invalid])):focus-visible {
53
- box-shadow:
53
+ box-shadow: var(
54
+ --ui-input-invalid-focus-shadow,
54
55
  var(--ui-control-inset),
55
- 0 0 0 3px color-mix(in srgb, var(--ui-danger-solid) 22%, transparent);
56
+ 0 0 0 3px color-mix(in srgb, var(--ui-danger-solid) 22%, transparent)
57
+ );
56
58
  }
57
59
 
58
60
  :scope:disabled {
@@ -62,6 +62,9 @@
62
62
  font-family: var(--ui-font-family-mono);
63
63
  }
64
64
 
65
+ /* A link in running text is underlined, so it stands apart from the words around it by more than
66
+ colour. */
67
+
65
68
  :scope[data-ui-text-state~="truncate"] {
66
69
  overflow: hidden;
67
70
  text-overflow: ellipsis;
@@ -81,5 +84,14 @@
81
84
  /* Running text, set on the type scale and in a tone that says what it is, so a view never styles
82
85
  text of its own. The root is a paragraph unless as= names a span, div, small, strong, or label. */
83
86
 
87
+ /* A link in running text is underlined, so it stands apart from the words around it by more than
88
+ colour. */
89
+ :scope :where([data-slotted], [data-slotted] *):is(a) {
90
+ color: var(--ui-accent-active);
91
+ text-decoration: underline;
92
+ text-decoration-thickness: 0.06em;
93
+ text-underline-offset: 0.18em;
94
+ }
95
+
84
96
  /* A component that sets its display still honours the hidden attribute on its root. */
85
97
  }
@@ -201,7 +201,7 @@
201
201
  /* A hovered row reads its whole name: the label slides far enough to show the end, waits
202
202
  there, and comes back. Only when it actually overflows — the controller measures by how
203
203
  much — after the controls have taken their place over its end — and hands over the distance
204
- and a duration from it, so a longer name travels no faster. */
204
+ and a duration from it, so every name moves at the same speed. */
205
205
  .row[data-ui-marquee] > .label > .label-text {
206
206
  /* Once, and it stays at the end while the pointer is there: a name that keeps sliding back
207
207
  and forth under the pointer is harder to read than one that arrives and holds. */
@@ -424,7 +424,7 @@
424
424
  /* A hovered row reads its whole name: the label slides far enough to show the end, waits
425
425
  there, and comes back. Only when it actually overflows — the controller measures by how
426
426
  much — after the controls have taken their place over its end — and hands over the distance
427
- and a duration from it, so a longer name travels no faster. */
427
+ and a duration from it, so every name moves at the same speed. */
428
428
 
429
429
  /* This comes after the hover fade, which it replaces at the same specificity. While the name
430
430
  slides, the label reaches back under the icon (the controller measures how far) with its text
package/vue/UiCallout.vue CHANGED
@@ -164,6 +164,14 @@ const hostState = computed(() =>
164
164
  --_callout-icon: var(--ui-danger-solid);
165
165
  }
166
166
 
167
+ /* A link in the callout's text is underlined, so it reads as a link by more than colour. */
168
+ .content :slotted(a) {
169
+ color: var(--ui-accent-active);
170
+ text-decoration: underline;
171
+ text-decoration-thickness: 0.06em;
172
+ text-underline-offset: 0.18em;
173
+ }
174
+
167
175
  /* A component that sets its display still honours the hidden attribute on its root. */
168
176
  [data-component~="ui-callout"][hidden] {
169
177
  display: none;
@@ -71,9 +71,10 @@ useComponentHost(controllerModule.default, {
71
71
  min-block-size: var(--ui-form-field-help-min-block-size, 0);
72
72
  }
73
73
 
74
+ /* An error reads in the danger colour, the one the invalid control's border takes. */
74
75
  .error,
75
76
  :slotted([role="alert"]) {
76
- color: var(--ui-accent-active);
77
+ color: var(--ui-danger);
77
78
  font-size: var(--ui-font-size-sm);
78
79
  }
79
80
 
package/vue/UiInput.vue CHANGED
@@ -108,13 +108,15 @@ useComponentHost(controllerModule.default, {
108
108
  /* The app's invalid flag, or the browser's own verdict once the user has left an invalid field. */
109
109
  [data-component~="ui-input"][aria-invalid="true"],
110
110
  [data-component~="ui-input"]:is(:user-invalid, [data-user-invalid]) {
111
- border-color: var(--ui-danger-solid);
111
+ border-color: var(--ui-input-invalid-border, var(--ui-danger-solid));
112
112
  }
113
113
 
114
114
  [data-component~="ui-input"]:is([aria-invalid="true"], :is(:user-invalid, [data-user-invalid])):focus-visible {
115
- box-shadow:
115
+ box-shadow: var(
116
+ --ui-input-invalid-focus-shadow,
116
117
  var(--ui-control-inset),
117
- 0 0 0 3px color-mix(in srgb, var(--ui-danger-solid) 22%, transparent);
118
+ 0 0 0 3px color-mix(in srgb, var(--ui-danger-solid) 22%, transparent)
119
+ );
118
120
  }
119
121
 
120
122
  [data-component~="ui-input"]:disabled {
@@ -44,6 +44,8 @@ const hostState = computed(() =>
44
44
  --ui-input-border: transparent;
45
45
  --ui-input-border-hover: transparent;
46
46
  --ui-input-focus-border: transparent;
47
+ --ui-input-invalid-border: transparent;
48
+ --ui-input-invalid-focus-shadow: none;
47
49
  --ui-input-shadow: none;
48
50
  --ui-input-focus-shadow: none;
49
51
  --ui-input-radius: 0;
package/vue/UiText.vue CHANGED
@@ -108,6 +108,15 @@ const hostState = computed(() =>
108
108
  font-family: var(--ui-font-family-mono);
109
109
  }
110
110
 
111
+ /* A link in running text is underlined, so it stands apart from the words around it by more than
112
+ colour. */
113
+ [data-component~="ui-text"] :slotted(a) {
114
+ color: var(--ui-accent-active);
115
+ text-decoration: underline;
116
+ text-decoration-thickness: 0.06em;
117
+ text-underline-offset: 0.18em;
118
+ }
119
+
111
120
  [data-component~="ui-text"][data-ui-text-state~="truncate"] {
112
121
  overflow: hidden;
113
122
  text-overflow: ellipsis;
@@ -378,7 +378,7 @@ useComponentHost(controllerModule.default, {
378
378
  /* A hovered row reads its whole name: the label slides far enough to show the end, waits
379
379
  there, and comes back. Only when it actually overflows — the controller measures by how
380
380
  much — after the controls have taken their place over its end — and hands over the distance
381
- and a duration from it, so a longer name travels no faster. */
381
+ and a duration from it, so every name moves at the same speed. */
382
382
  .row[data-ui-marquee] > .label > .label-text {
383
383
  /* Once, and it stays at the end while the pointer is there: a name that keeps sliding back
384
384
  and forth under the pointer is harder to read than one that arrives and holds. */
@@ -100,9 +100,9 @@ var UiCallout_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
100
100
  createElementVNode("path", { d: "m15 9-6 6" }, null, -1),
101
101
  createElementVNode("path", { d: "m9 9 6 6" }, null, -1)
102
102
  ])])) : createCommentVNode("v-if", true)
103
- ]), createElementVNode("div", _hoisted_8, [renderSlot(_ctx.$slots, "default", {}, void 0, true)])], 16, _hoisted_1);
103
+ ]), createElementVNode("div", _hoisted_8, [renderSlot(_ctx.$slots, "default")])], 16, _hoisted_1);
104
104
  };
105
105
  }
106
- }), [["__scopeId", "data-v-2fd6ab30"]]);
106
+ }), [["__scopeId", "data-v-36fb7e55"]]);
107
107
  //#endregion
108
108
  export { UiCallout_default as t };
@@ -46,6 +46,6 @@ var UiFormField_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
46
46
  ], 16);
47
47
  };
48
48
  }
49
- }), [["__scopeId", "data-v-eba1e76b"]]);
49
+ }), [["__scopeId", "data-v-4df6c2a6"]]);
50
50
  //#endregion
51
51
  export { UiFormField_default as t };
@@ -61,6 +61,6 @@ var UiInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
61
61
  }), null, 16, _hoisted_1)), [[vModelDynamic, model.value]]);
62
62
  };
63
63
  }
64
- }), [["__scopeId", "data-v-12ffae5a"]]);
64
+ }), [["__scopeId", "data-v-c19f8322"]]);
65
65
  //#endregion
66
66
  export { UiInput_default as t };
@@ -26,6 +26,6 @@ var UiInputGroup_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
26
26
  ], 16, _hoisted_1);
27
27
  };
28
28
  }
29
- }), [["__scopeId", "data-v-0a135fc1"]]);
29
+ }), [["__scopeId", "data-v-42ff173c"]]);
30
30
  //#endregion
31
31
  export { UiInputGroup_default as t };
@@ -30,11 +30,11 @@ var UiText_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
30
30
  ].filter(Boolean).join(" "));
31
31
  return (_ctx, _cache) => {
32
32
  return openBlock(), createBlock(resolveDynamicComponent(__props.as), mergeProps({ "data-component": "ui-text" }, _ctx.$attrs, { "data-ui-text-state": hostState.value || void 0 }), {
33
- default: withCtx(() => [renderSlot(_ctx.$slots, "default", {}, void 0, true)]),
33
+ default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
34
34
  _: 3
35
35
  }, 16, ["data-ui-text-state"]);
36
36
  };
37
37
  }
38
- }), [["__scopeId", "data-v-70a75450"]]);
38
+ }), [["__scopeId", "data-v-b83a3ab9"]]);
39
39
  //#endregion
40
40
  export { UiText_default as t };
@@ -234,6 +234,6 @@ var UiTreeItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
234
234
  ], 16, _hoisted_1);
235
235
  };
236
236
  }
237
- }), [["__scopeId", "data-v-3778b642"]]);
237
+ }), [["__scopeId", "data-v-dab96891"]]);
238
238
  //#endregion
239
239
  export { UiTreeItem_default as t };