@things-factory/shell 10.1.26 → 10.1.27

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": "@things-factory/shell",
3
- "version": "10.1.26",
3
+ "version": "10.1.27",
4
4
  "description": "Core module for framework",
5
5
  "bin": {
6
6
  "things-factory": "bin/things-factory",
@@ -126,5 +126,5 @@
126
126
  "pg": "^8.7.3",
127
127
  "sqlite3": "^5.0.8"
128
128
  },
129
- "gitHead": "151bda14d899442c6846532ddded1e2bfe23a2f5"
129
+ "gitHead": "d04dc762cacf2aac8ba0b0f5d768eca365fc09da"
130
130
  }
@@ -5,8 +5,8 @@
5
5
  * together - change one and it fails until the other follows.
6
6
  *
7
7
  * Two bundles: button heights (ACTION_HEIGHT_TOKENS, ui-tokens.css) and input heights
8
- * (FORM_ELEMENT_HEIGHT_TOKENS, spacing.css). Material buttons, text fields, selects and chips are
9
- * sized once in the theme from those tokens.
8
+ * (FORM_ELEMENT_HEIGHT_TOKENS, spacing.css). Material buttons and filter chips are sized once in the
9
+ * theme from those tokens; Material text fields and selects keep their own size.
10
10
  */
11
11
 
12
12
  import { existsSync, readFileSync } from 'fs'
@@ -33,14 +33,19 @@ function themeDeclarations(file: string): Record<string, string> {
33
33
  return Object.fromEntries([...css.matchAll(/(--[a-z0-9-]+)\s*:\s*([^;]+);/g)].map(m => [m[1], m[2].trim()]))
34
34
  }
35
35
 
36
- function expectSameValues(constants: Record<string, number>, theme: Record<string, string>) {
36
+ function expectPlatformSlots(constants: Record<string, number>, theme: Record<string, string>) {
37
+ /*
38
+ * Each token opens a slot for operato-suite and falls back to the platform default
39
+ * (ADR-0060 decision 6-1). The suite never redefines the token itself, so nothing depends on which
40
+ * stylesheet loads last.
41
+ */
37
42
  for (const [token, px] of Object.entries(constants)) {
38
- expect({ token, value: theme[token] }).toEqual({ token, value: `${px}px` })
43
+ expect({ token, value: theme[token] }).toEqual({ token, value: `var(--suite-${token.slice(2)}, ${px}px)` })
39
44
  }
40
45
  }
41
46
 
42
47
  describe('button height tokens', () => {
43
- it('the shell theme declares every @operato/styles action height with the same value', () => {
48
+ it('the shell theme opens every @operato/styles action height as a suite slot over the platform default', () => {
44
49
  const constants = stylesConstants('action-heights.js', 'ACTION_HEIGHT_TOKENS')
45
50
 
46
51
  expect(Object.keys(constants).sort()).toEqual([
@@ -49,7 +54,7 @@ describe('button height tokens', () => {
49
54
  '--form-action-height',
50
55
  '--popup-action-height'
51
56
  ])
52
- expectSameValues(constants, themeDeclarations('ui-tokens.css'))
57
+ expectPlatformSlots(constants, themeDeclarations('ui-tokens.css'))
53
58
  })
54
59
 
55
60
  it('Material buttons take the form height, set once in the theme', () => {
@@ -63,15 +68,19 @@ describe('button height tokens', () => {
63
68
  }
64
69
  })
65
70
 
66
- it('assist chips draw page actions, so they take the page action height', () => {
67
- expect(themeDeclarations('layout-theme.css')['--md-assist-chip-container-height']).toBe(
68
- 'var(--context-action-height)'
69
- )
71
+ it('assist chips: 36px (44px by finger) on the platform, the page action height in the operato products', () => {
72
+ const css = readFileSync(path.join(THEMES, 'layout-theme.css'), 'utf-8').replace(/\/\*[\s\S]*?\*\//g, '')
73
+ const values = [...css.matchAll(/--md-assist-chip-container-height\s*:\s*([^;]+);/g)].map(m => m[1].trim())
74
+
75
+ expect(values).toEqual([
76
+ 'var(--suite-context-action-height, 36px)',
77
+ 'var(--suite-context-action-height, var(--ui-tap, 44px))'
78
+ ])
70
79
  })
71
80
  })
72
81
 
73
82
  describe('input height tokens', () => {
74
- it('the shell theme declares small, medium and large with the @operato/styles values, and nothing else', () => {
83
+ it('the shell theme opens small, medium and large as suite slots over the platform defaults, and nothing else', () => {
75
84
  const constants = stylesConstants('form-element-heights.js', 'FORM_ELEMENT_HEIGHT_TOKENS')
76
85
  const theme = themeDeclarations('spacing.css')
77
86
 
@@ -80,7 +89,7 @@ describe('input height tokens', () => {
80
89
  '--form-element-height-medium',
81
90
  '--form-element-height-small'
82
91
  ])
83
- expectSameValues(constants, theme)
92
+ expectPlatformSlots(constants, theme)
84
93
  expect(
85
94
  Object.keys(theme)
86
95
  .filter(name => name.startsWith('--form-element-height-'))
@@ -88,55 +97,17 @@ describe('input height tokens', () => {
88
97
  ).toEqual(Object.keys(constants).sort())
89
98
  })
90
99
 
91
- it('an input lines up with a button on the same row (a UX layout rule)', () => {
92
- /*
93
- * The tokens are separate so one use can change on its own (user decision 2026-09-17). This test
94
- * is a layout rule on top of that: a field and a button that stand on one row have one height.
95
- * If a change here is intended, change this rule - do not put the value back to make it pass.
96
- */
97
- const actions = stylesConstants('action-heights.js', 'ACTION_HEIGHT_TOKENS')
98
- const inputs = stylesConstants('form-element-heights.js', 'FORM_ELEMENT_HEIGHT_TOKENS')
99
- const pairs = [
100
- ['--form-element-height-medium', '--form-action-height'],
101
- ['--form-element-height-small', '--cell-action-height']
102
- ] as const
103
-
104
- for (const [input, button] of pairs) {
105
- if (inputs[input] !== actions[button]) {
106
- throw new Error(
107
- `${input} (${inputs[input]}px) and ${button} (${actions[button]}px) stand on one row but differ in height. ` +
108
- 'If that is intended, change this layout rule; do not put the value back to make it pass.'
109
- )
110
- }
111
- }
112
- })
113
-
114
- it('outlined Material fields take medium, filled ones take large', () => {
100
+ it('Material text fields, selects and filter chips keep their own size', () => {
101
+ /* Their label floats above the value inside the box and needs the room (user decision). */
115
102
  const theme = themeDeclarations('material-theme.css')
116
- const space = (size: string, less: number) => `calc((var(--form-element-height-${size}) - ${less}px) / 2)`
117
-
118
- for (const name of [
119
- '--md-outlined-text-field-top-space',
120
- '--md-outlined-text-field-bottom-space',
121
- '--md-outlined-field-top-space',
122
- '--md-outlined-field-bottom-space'
123
- ]) {
124
- expect({ name, value: theme[name] }).toEqual({ name, value: space('medium', 20) })
125
- }
126
-
127
- for (const name of [
128
- '--md-filled-text-field-top-space',
129
- '--md-filled-text-field-bottom-space',
130
- '--md-filled-field-top-space',
131
- '--md-filled-field-bottom-space'
132
- ]) {
133
- expect({ name, value: theme[name] }).toEqual({ name, value: space('large', 20) })
134
- }
135
-
136
- for (const name of ['--md-filled-text-field-with-label-top-space', '--md-filled-field-with-label-bottom-space']) {
137
- expect({ name, value: theme[name] }).toEqual({ name, value: space('large', 34) })
138
- }
103
+ const fieldSizes = Object.keys(theme).filter(name =>
104
+ /^--md-(outlined|filled)-(text-field|select-text-field|field|select)-.*(space|height|text-size|line-height|populated-size)$/.test(
105
+ name
106
+ )
107
+ )
139
108
 
140
- expect(theme['--md-filter-chip-container-height']).toBe('var(--form-element-height-small)')
109
+ expect(fieldSizes).toEqual([])
110
+ /* filter chips keep Material's size on the platform; ox-input-select-buttons sizes its own */
111
+ expect(theme['--md-filter-chip-container-height']).toBeUndefined()
141
112
  })
142
113
  })