@lowdefy/blocks-antd-x 6.0.0 → 7.0.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.
@@ -0,0 +1,159 @@
1
+ .root {
2
+ border: 1px solid var(--border);
3
+ border-radius: 20px;
4
+ background: var(--bg);
5
+ box-shadow:
6
+ 0 1px 2px rgb(0 0 0 / 4%),
7
+ 0 10px 30px -14px rgb(0 0 0 / 18%);
8
+ transition:
9
+ border-color 320ms ease,
10
+ box-shadow 320ms ease;
11
+ overflow: hidden;
12
+ }
13
+
14
+ .root[data-mode='committed'] {
15
+ border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
16
+ box-shadow:
17
+ 0 0 0 4px color-mix(in srgb, var(--accent) 12%, transparent),
18
+ 0 14px 36px -18px color-mix(in srgb, var(--accent) 55%, transparent);
19
+ }
20
+
21
+ .field {
22
+ display: flex;
23
+ align-items: center;
24
+ gap: 10px;
25
+ padding: 16px 20px;
26
+ }
27
+
28
+ .input {
29
+ flex: 1;
30
+ min-width: 0;
31
+ border: 0;
32
+ outline: 0;
33
+ background: transparent;
34
+ color: var(--text);
35
+ font: inherit;
36
+ font-size: 18px;
37
+ }
38
+
39
+ .input::placeholder {
40
+ color: var(--muted);
41
+ }
42
+
43
+ .badge {
44
+ display: inline-flex;
45
+ align-items: center;
46
+ gap: 6px;
47
+ padding: 3px 10px;
48
+ border: 1px dashed var(--border);
49
+ border-radius: 999px;
50
+ color: var(--muted);
51
+ font-size: 12px;
52
+ white-space: nowrap;
53
+ animation: pop 220ms cubic-bezier(0.2, 0.9, 0.3, 1.25);
54
+ transition:
55
+ color 260ms ease,
56
+ background 260ms ease,
57
+ border-color 260ms ease;
58
+ }
59
+
60
+ .root[data-mode='committed'] .badge {
61
+ border-color: transparent;
62
+ background: color-mix(in srgb, var(--accent) 16%, transparent);
63
+ color: color-mix(in srgb, var(--accent) 60%, var(--text));
64
+ }
65
+
66
+ .morph {
67
+ overflow: hidden;
68
+ transition: height 360ms cubic-bezier(0.2, 0.8, 0.2, 1);
69
+ }
70
+
71
+ .inner:not(:empty) {
72
+ border-top: 1px solid var(--border);
73
+ }
74
+
75
+ .choices {
76
+ display: flex;
77
+ flex-wrap: wrap;
78
+ align-items: center;
79
+ gap: 8px;
80
+ padding: 12px 20px 0;
81
+ animation: rise 220ms ease;
82
+ }
83
+
84
+ .choicesLabel {
85
+ color: var(--muted);
86
+ font-size: 13px;
87
+ }
88
+
89
+ .choice {
90
+ display: inline-flex;
91
+ align-items: center;
92
+ gap: 6px;
93
+ padding: 4px 12px;
94
+ border: 1px solid var(--border);
95
+ border-radius: 999px;
96
+ background: transparent;
97
+ color: var(--text);
98
+ font: inherit;
99
+ font-size: 13px;
100
+ cursor: pointer;
101
+ transition:
102
+ border-color 160ms ease,
103
+ color 160ms ease;
104
+ }
105
+
106
+ .choice:hover {
107
+ border-color: var(--accent);
108
+ color: color-mix(in srgb, var(--accent) 60%, var(--text));
109
+ }
110
+
111
+ .slot {
112
+ padding: 16px 20px 20px;
113
+ animation: rise 340ms cubic-bezier(0.2, 0.8, 0.2, 1);
114
+ transform-origin: top center;
115
+ transition:
116
+ opacity 280ms ease,
117
+ filter 280ms ease,
118
+ transform 280ms ease;
119
+ }
120
+
121
+ .slot[data-preview='true'] {
122
+ opacity: 0.42;
123
+ filter: saturate(0.2) blur(0.6px);
124
+ transform: scale(0.985);
125
+ pointer-events: none;
126
+ }
127
+
128
+ @keyframes rise {
129
+ from {
130
+ opacity: 0;
131
+ transform: translateY(8px) scale(0.985);
132
+ }
133
+ to {
134
+ opacity: 1;
135
+ transform: none;
136
+ }
137
+ }
138
+
139
+ @keyframes pop {
140
+ from {
141
+ opacity: 0;
142
+ transform: scale(0.85);
143
+ }
144
+ to {
145
+ opacity: 1;
146
+ transform: none;
147
+ }
148
+ }
149
+
150
+ @media (prefers-reduced-motion: reduce) {
151
+ .root,
152
+ .badge,
153
+ .morph,
154
+ .choices,
155
+ .slot {
156
+ animation: none;
157
+ transition: none;
158
+ }
159
+ }
@@ -0,0 +1,34 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ // A Decide choice answer ({ choice, confidence, probabilities }) as a score per
16
+ // intent. Options without an intent (such as a `none` escape option) drop out.
17
+ // The provider's calibrated confidence, where it reports one, is the chosen
18
+ // intent's score, and the other intents keep their ratio to it: mixing calibrated
19
+ // and raw scores could rank a rival above the intent the model chose.
20
+ function answerScores({ answer, intents }) {
21
+ const probabilities = answer?.probabilities ?? {};
22
+ const chosen = Object.hasOwn(intents, answer?.choice ?? '') ? answer.choice : null;
23
+ let scale = 1;
24
+ if (chosen && Number.isFinite(answer.confidence) && probabilities[chosen] > 0) {
25
+ scale = answer.confidence / probabilities[chosen];
26
+ }
27
+ const scores = {};
28
+ Object.keys(intents).forEach((key)=>{
29
+ if (Number.isFinite(probabilities[key])) scores[key] = probabilities[key] * scale;
30
+ });
31
+ if (chosen && Number.isFinite(answer.confidence)) scores[chosen] = answer.confidence;
32
+ return scores;
33
+ }
34
+ export default answerScores;
@@ -0,0 +1,81 @@
1
+ # Copyright 2020-2026 Lowdefy, Inc
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # A keyword classifier stands in for a Decide request so the example runs
16
+ # without a model. Try "fix the login bug", "sync with Sam friday 2pm" or
17
+ # "standup".
18
+ - title: Capture box
19
+ blocks:
20
+ - id: capture_demo
21
+ type: IntentInput
22
+ properties:
23
+ placeholder: Try "fix the login bug" or "sync with Sam friday 2pm"
24
+ intents:
25
+ task:
26
+ label: Task
27
+ icon: CircleCheck
28
+ color: '#6366f1'
29
+ meeting:
30
+ label: Meeting
31
+ icon: Calendar
32
+ color: '#0ea5e9'
33
+ answer:
34
+ _state: capture_demo_answer
35
+ events:
36
+ onClassify:
37
+ - id: classify
38
+ type: SetState
39
+ params:
40
+ capture_demo_answer:
41
+ _js:
42
+ fn: |
43
+ const text = args.text.toLowerCase();
44
+ const probabilities = { task: 0.05, meeting: 0.05 };
45
+ if (/^(fix|add|build|update|remove)\b/.test(text)) probabilities.task = 0.9;
46
+ if (/\b(sync|meeting|call|standup)\b/.test(text)) {
47
+ probabilities.meeting = /\d|today|tomorrow|day\b/.test(text) ? 0.9 : 0.4;
48
+ }
49
+ return { probabilities };
50
+ args:
51
+ text:
52
+ _event: text
53
+ slots:
54
+ task:
55
+ blocks:
56
+ - id: capture_demo_task
57
+ type: Paragraph
58
+ properties:
59
+ content:
60
+ _string.concat:
61
+ - 'New task: '
62
+ - _state: capture_demo.text
63
+ - id: capture_demo_create
64
+ type: Button
65
+ properties:
66
+ title: Create task
67
+ type: primary
68
+ meeting:
69
+ blocks:
70
+ - id: capture_demo_meeting
71
+ type: Paragraph
72
+ properties:
73
+ content:
74
+ _string.concat:
75
+ - 'New meeting: '
76
+ - _state: capture_demo.text
77
+ - id: capture_demo_invite
78
+ type: Button
79
+ properties:
80
+ title: Send invite
81
+ type: primary
@@ -0,0 +1,164 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ const level = {
16
+ type: 'number',
17
+ minimum: 0,
18
+ maximum: 1
19
+ };
20
+ const mode = '`idle` (nothing recognised), `preview`, `choose` or `committed`.';
21
+ export default {
22
+ // An input with slots: its value is { text, intent, mode }, and each intent shows the
23
+ // slot named after it, so slot names are authored and cannot be enumerated.
24
+ category: 'input-container',
25
+ icons: [],
26
+ valueType: 'object',
27
+ slots: false,
28
+ cssKeys: {
29
+ element: 'The IntentInput element.'
30
+ },
31
+ events: {
32
+ onChange: {
33
+ description: 'Trigger actions when the user types.',
34
+ event: {
35
+ text: 'The current text.'
36
+ }
37
+ },
38
+ onClassify: {
39
+ description: 'Trigger actions shortly after the text changes, to classify it. Typically runs a Decide request whose answer is passed back as `answer`.',
40
+ event: {
41
+ text: 'The text to classify.'
42
+ }
43
+ },
44
+ onIntentChange: {
45
+ description: 'Trigger actions when the shown intent or its mode changes.',
46
+ event: {
47
+ intent: 'The shown intent, or null.',
48
+ mode
49
+ }
50
+ },
51
+ onSubmit: {
52
+ description: 'Trigger actions when Enter is pressed.',
53
+ event: {
54
+ text: 'The current text.',
55
+ intent: 'The shown intent, or null.',
56
+ mode
57
+ }
58
+ }
59
+ },
60
+ properties: {
61
+ type: 'object',
62
+ additionalProperties: false,
63
+ properties: {
64
+ autoFocus: {
65
+ type: 'boolean',
66
+ description: 'Focus the input on mount.'
67
+ },
68
+ placeholder: {
69
+ type: 'string',
70
+ description: 'Placeholder text.'
71
+ },
72
+ intents: {
73
+ type: 'object',
74
+ description: 'The intents the text can become, by name. Each name is also the slot shown for it. The same object can be the options of the Decide question that classifies the text.',
75
+ docs: {
76
+ displayType: 'yaml'
77
+ },
78
+ additionalProperties: {
79
+ type: 'object',
80
+ additionalProperties: false,
81
+ properties: {
82
+ label: {
83
+ type: 'string',
84
+ description: 'Name shown on the badge and choices.'
85
+ },
86
+ icon: {
87
+ type: [
88
+ 'string',
89
+ 'object'
90
+ ],
91
+ description: 'Icon name or Icon block properties for the badge and choices.'
92
+ },
93
+ color: {
94
+ type: 'string',
95
+ description: 'Accent color of the edge and badge.'
96
+ },
97
+ description: {
98
+ type: 'string',
99
+ description: 'What the intent means. Read by the classifier, not shown.'
100
+ }
101
+ }
102
+ }
103
+ },
104
+ answer: {
105
+ type: [
106
+ 'object',
107
+ 'null'
108
+ ],
109
+ description: 'The classification of the current text, in the shape of a Decide choice answer: `_request: classify.intent`. Options that are not intents, such as a `none` option, are ignored. While a new answer loads, the last one is kept.',
110
+ docs: {
111
+ displayType: 'yaml'
112
+ },
113
+ properties: {
114
+ choice: {
115
+ type: [
116
+ 'string',
117
+ 'null'
118
+ ]
119
+ },
120
+ confidence: {
121
+ type: [
122
+ 'number',
123
+ 'null'
124
+ ]
125
+ },
126
+ probabilities: {
127
+ type: [
128
+ 'object',
129
+ 'null'
130
+ ],
131
+ additionalProperties: {
132
+ type: 'number'
133
+ }
134
+ }
135
+ }
136
+ },
137
+ confidence: {
138
+ type: 'object',
139
+ additionalProperties: false,
140
+ description: 'How sure the answer must be before the slot changes how it looks.',
141
+ docs: {
142
+ displayType: 'yaml'
143
+ },
144
+ properties: {
145
+ preview: {
146
+ ...level,
147
+ default: 0.3,
148
+ description: 'Show a faded preview of the slot from this confidence.'
149
+ },
150
+ show: {
151
+ ...level,
152
+ default: 0.6,
153
+ description: 'Commit to the intent and show its slot solid from this confidence.'
154
+ },
155
+ switch: {
156
+ ...level,
157
+ default: 0.85,
158
+ description: 'Replace the shown intent at once from this confidence. Below it, another intent must lead twice in a row, or hold the lead while the user pauses.'
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ };
@@ -0,0 +1,62 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ // When the two leading intents are this close and neither is committed, offer both.
16
+ const CHOICE_MARGIN = 0.15;
17
+ // Classifier scores jump around while the user is mid-word, so the shown intent
18
+ // only changes when a challenger leads two rounds in a row or reaches the
19
+ // `switch` confidence. The block re-runs a round with unchanged scores after a
20
+ // pause, so a challenger that holds the lead while the user stops typing also wins.
21
+ // `intent: null` is "nothing recognised"; `challenger: undefined` is "no challenger",
22
+ // so a null challenger can still take the intent back to idle.
23
+ function nextIntentState({ state, scores, confidence }) {
24
+ const ranked = Object.entries(scores).filter(([, p])=>Number.isFinite(p)).sort((a, b)=>b[1] - a[1]);
25
+ const top = ranked[0];
26
+ const candidate = top && top[1] >= confidence.preview ? top[0] : null;
27
+ let { intent, challenger } = state;
28
+ if (candidate === intent) {
29
+ challenger = undefined;
30
+ } else if (challenger === candidate || (top?.[1] ?? 0) >= confidence.switch) {
31
+ intent = candidate;
32
+ challenger = undefined;
33
+ } else {
34
+ challenger = candidate;
35
+ }
36
+ if (intent === null) return {
37
+ intent,
38
+ challenger,
39
+ mode: 'idle',
40
+ choices: []
41
+ };
42
+ const p = scores[intent] ?? 0;
43
+ const rival = ranked.find(([key])=>key !== intent);
44
+ if (p < confidence.show && rival && rival[1] >= confidence.preview && Math.abs(p - rival[1]) < CHOICE_MARGIN) {
45
+ return {
46
+ intent,
47
+ challenger,
48
+ mode: 'choose',
49
+ choices: [
50
+ intent,
51
+ rival[0]
52
+ ]
53
+ };
54
+ }
55
+ return {
56
+ intent,
57
+ challenger,
58
+ mode: p >= confidence.show ? 'committed' : 'preview',
59
+ choices: []
60
+ };
61
+ }
62
+ export default nextIntentState;
package/dist/blocks.js CHANGED
@@ -14,3 +14,4 @@
14
14
  limitations under the License.
15
15
  */ export { default as AgentChat } from './blocks/AgentChat/AgentChat.js';
16
16
  export { default as AgentConversations } from './blocks/AgentConversations/AgentConversations.js';
17
+ export { default as IntentInput } from './blocks/IntentInput/IntentInput.js';
package/dist/metas.js CHANGED
@@ -14,3 +14,4 @@
14
14
  limitations under the License.
15
15
  */ export { default as AgentChat } from './blocks/AgentChat/meta.js';
16
16
  export { default as AgentConversations } from './blocks/AgentConversations/meta.js';
17
+ export { default as IntentInput } from './blocks/IntentInput/meta.js';
package/dist/types.js CHANGED
@@ -12,21 +12,6 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ export default {
16
- blocks: [
17
- 'AgentChat',
18
- 'AgentConversations'
19
- ],
20
- icons: {
21
- AgentChat: [],
22
- AgentConversations: []
23
- },
24
- blockMetas: {
25
- AgentChat: {
26
- category: 'display'
27
- },
28
- AgentConversations: {
29
- category: 'display'
30
- }
31
- }
32
- };
15
+ */ import { extractBlockTypes } from '@lowdefy/block-utils';
16
+ import * as metas from './metas.js';
17
+ export default extractBlockTypes(metas);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/blocks-antd-x",
3
- "version": "6.0.0",
3
+ "version": "7.0.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Lowdefy Ant Design X Blocks",
6
6
  "homepage": "https://lowdefy.com",
@@ -29,6 +29,9 @@
29
29
  "url": "https://github.com/lowdefy/lowdefy.git"
30
30
  },
31
31
  "type": "module",
32
+ "sideEffects": [
33
+ "**/*.css"
34
+ ],
32
35
  "exports": {
33
36
  "./blocks": "./dist/blocks.js",
34
37
  "./types": "./dist/types.js"
@@ -37,25 +40,25 @@
37
40
  "dist/*"
38
41
  ],
39
42
  "dependencies": {
40
- "@ai-sdk/react": "3.0.178",
41
- "@ant-design/icons": "6.1.0",
42
- "@ant-design/x": "2.7.0",
43
- "@ant-design/x-markdown": "2.7.0",
44
- "@lowdefy/block-utils": "6.0.0",
45
- "@lowdefy/blocks-files": "6.0.0",
46
- "@lowdefy/helpers": "6.0.0",
47
- "ai": "6.0.176"
43
+ "@ai-sdk/react": "4.0.119",
44
+ "@ant-design/x": "2.9.0",
45
+ "@ant-design/x-markdown": "2.9.0",
46
+ "@lowdefy/block-utils": "7.0.0",
47
+ "@lowdefy/blocks-files": "7.0.0",
48
+ "@lowdefy/helpers": "7.0.0",
49
+ "ai": "7.0.116"
48
50
  },
49
51
  "devDependencies": {
50
- "@lowdefy/block-dev-e2e": "6.0.0",
51
- "@lowdefy/e2e-utils": "6.0.0",
52
+ "@lowdefy/block-dev-e2e": "7.0.0",
53
+ "@lowdefy/e2e-utils": "7.0.0",
52
54
  "@playwright/test": "1.59.1",
53
55
  "@swc/cli": "0.8.1",
54
56
  "@swc/core": "1.15.32",
55
- "copyfiles": "2.4.1"
57
+ "copyfiles": "2.4.1",
58
+ "react-dom": "18.2.0"
56
59
  },
57
60
  "peerDependencies": {
58
- "antd": "6.3.1",
61
+ "antd": "6.6.5",
59
62
  "react": "18.2.0"
60
63
  },
61
64
  "publishConfig": {