@destyler-ui/svelte 0.0.1-beta.17 → 0.0.1-beta.21

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 (97) hide show
  1. package/README.md +7 -1
  2. package/dist/components/aspect-ratio/components/Root.svelte +1 -2
  3. package/dist/components/aspect-ratio/hooks/use-aspect-ratio.svelte.d.ts +0 -1
  4. package/dist/components/aspect-ratio/hooks/use-aspect-ratio.svelte.js +1 -1
  5. package/dist/components/calendar/anatomy.d.ts +1 -1
  6. package/dist/components/calendar/components/Content.d.svelte.ts +1 -1
  7. package/dist/components/calendar/components/Content.svelte +2 -3
  8. package/dist/components/calendar/components/Content.svelte.d.ts +1 -1
  9. package/dist/components/calendar/components/Root.svelte +14 -8
  10. package/dist/components/calendar/hooks/use-calendar.svelte.d.ts +1 -1
  11. package/dist/components/calendar/hooks/use-calendar.svelte.js +13 -3
  12. package/dist/components/carousel/components/Root.svelte +9 -3
  13. package/dist/components/checkbox/components/Group.svelte +8 -2
  14. package/dist/components/checkbox/components/Root.svelte +8 -2
  15. package/dist/components/checkbox/hooks/use-checkbox-group.svelte.d.ts +17 -7
  16. package/dist/components/checkbox/hooks/use-checkbox-group.svelte.js +7 -4
  17. package/dist/components/checkbox/hooks/use-checkbox.svelte.js +14 -2
  18. package/dist/components/collapse/components/Root.svelte +9 -3
  19. package/dist/components/collapsible/components/Root.svelte +9 -3
  20. package/dist/components/collapsible/hooks/split-collapsible-props.svelte.d.ts +1 -1
  21. package/dist/components/collapsible/hooks/use-collapsible.svelte.d.ts +1 -1
  22. package/dist/components/color-picker/anatomy.d.ts +1 -1
  23. package/dist/components/color-picker/components/ChannelInput.svelte +9 -1
  24. package/dist/components/color-picker/components/Root.svelte +12 -4
  25. package/dist/components/color-picker/hooks/split-color-picker-props.svelte.d.ts +1 -1
  26. package/dist/components/color-picker/hooks/use-color-picker.svelte.d.ts +1 -1
  27. package/dist/components/combobox/components/Content.svelte +4 -7
  28. package/dist/components/combobox/components/Root.svelte +12 -6
  29. package/dist/components/combobox/hooks/use-combobox.svelte.d.ts +1 -1
  30. package/dist/components/combobox/hooks/use-combobox.svelte.js +13 -1
  31. package/dist/components/dialog/components/Root.svelte +10 -3
  32. package/dist/components/dialog/hooks/use-dialog.svelte.d.ts +1 -1
  33. package/dist/components/dynamic/components/Root.svelte +11 -3
  34. package/dist/components/dynamic/hooks/use-dynamic.svelte.js +26 -13
  35. package/dist/components/edit/components/Root.svelte +12 -5
  36. package/dist/components/edit/hooks/use-edit.svelte.d.ts +1 -1
  37. package/dist/components/edit/hooks/use-edit.svelte.js +25 -3
  38. package/dist/components/floating-panel/components/Root.svelte +17 -7
  39. package/dist/components/floating-panel/hooks/use-floating-panel.svelte.d.ts +1 -1
  40. package/dist/components/floating-panel/hooks/use-floating-panel.svelte.js +0 -5
  41. package/dist/components/hover-card/components/Root.svelte +9 -3
  42. package/dist/components/hover-card/hooks/use-hover-card.svelte.d.ts +1 -1
  43. package/dist/components/menu/components/CheckboxItem.svelte +9 -3
  44. package/dist/components/menu/components/RadioItemGroup.svelte +5 -2
  45. package/dist/components/menu/components/Root.svelte +9 -3
  46. package/dist/components/menu/hooks/use-menu.svelte.d.ts +1 -1
  47. package/dist/components/navigation-menu/components/Root.svelte +3 -3
  48. package/dist/components/navigation-menu/hooks/connect-navigation-menu.d.ts +10 -0
  49. package/dist/components/navigation-menu/hooks/connect-navigation-menu.js +42 -0
  50. package/dist/components/navigation-menu/hooks/use-navigation-menu.svelte.d.ts +1 -2
  51. package/dist/components/navigation-menu/hooks/use-navigation-menu.svelte.js +11 -21
  52. package/dist/components/number-input/components/Root.svelte +8 -2
  53. package/dist/components/number-input/hooks/use-number-input.svelte.js +183 -2
  54. package/dist/components/otp-input/components/Input.svelte +6 -1
  55. package/dist/components/otp-input/components/Root.svelte +8 -2
  56. package/dist/components/pagination/components/Root.svelte +14 -5
  57. package/dist/components/popover/components/Root.svelte +10 -3
  58. package/dist/components/popover/hooks/use-popover.svelte.d.ts +1 -1
  59. package/dist/components/presence/components/Presence.svelte +6 -0
  60. package/dist/components/progress/components/Root.svelte +8 -2
  61. package/dist/components/progress/hooks/use-progress.svelte.js +17 -3
  62. package/dist/components/qr-code/components/Root.svelte +8 -2
  63. package/dist/components/qr-code/hooks/use-qr-code.svelte.js +14 -4
  64. package/dist/components/radio/components/Root.svelte +9 -3
  65. package/dist/components/radio/hooks/use-radio.svelte.js +10 -1
  66. package/dist/components/scroll-area/hooks/use-scroll-area.svelte.js +0 -28
  67. package/dist/components/select/components/Root.svelte +7 -3
  68. package/dist/components/select/hooks/use-select.svelte.d.ts +1 -1
  69. package/dist/components/slider/components/DraggingIndicator.svelte +3 -3
  70. package/dist/components/slider/components/Root.svelte +8 -2
  71. package/dist/components/slider/components/ThumbPropsProvider.svelte +4 -2
  72. package/dist/components/splitter/components/Root.svelte +9 -3
  73. package/dist/components/steps/components/Root.svelte +9 -3
  74. package/dist/components/steps/hooks/split-steps-props.svelte.d.ts +1 -1
  75. package/dist/components/switch/components/Root.svelte +9 -3
  76. package/dist/components/switch/hooks/use-switch.svelte.d.ts +12 -1
  77. package/dist/components/switch/hooks/use-switch.svelte.js +10 -1
  78. package/dist/components/tabs/components/Root.svelte +9 -3
  79. package/dist/components/toggle/components/Root.svelte +8 -2
  80. package/dist/components/toggle-group/components/Root.svelte +9 -3
  81. package/dist/components/tooltip/components/Root.svelte +9 -3
  82. package/dist/components/tooltip/hooks/use-tooltip.svelte.d.ts +1 -1
  83. package/dist/components/tree/components/BranchTrigger.d.svelte.ts +2 -2
  84. package/dist/components/tree/components/BranchTrigger.svelte +3 -3
  85. package/dist/components/tree/components/BranchTrigger.svelte.d.ts +2 -2
  86. package/dist/components/tree/components/Root.svelte +8 -3
  87. package/dist/components/tree/hooks/tree-split-props.d.ts +1 -1
  88. package/dist/providers/frame/components/Content.svelte +4 -1
  89. package/dist/utils/create-machine-props.d.ts +18 -7
  90. package/dist/utils/create-machine-props.js +22 -18
  91. package/dist/utils/sync-checked.d.ts +6 -0
  92. package/dist/utils/sync-checked.js +28 -0
  93. package/dist/utils/sync-input-value.d.ts +4 -0
  94. package/dist/utils/sync-input-value.js +27 -0
  95. package/dist/utils/sync-number-input.d.ts +2 -0
  96. package/dist/utils/sync-number-input.js +45 -0
  97. package/package.json +72 -68
@@ -3,8 +3,13 @@ import { useEnvironmentContext } from '../../../providers/environment/index.js';
3
3
  import { useLocaleContext } from '../../../providers/locale/index.js';
4
4
  import { createMachineProps } from '../../../utils/create-machine-props.js';
5
5
  import { normalizeProps } from '../../../utils/normalize-props.js';
6
+ import { createInputValueSync } from '../../../utils/sync-input-value.js';
7
+ import { syncNumberInputElement } from '../../../utils/sync-number-input.js';
8
+ import { createScope } from '@destyler/dom';
6
9
  import * as numberInput from '@destyler/number-input';
10
+ import { mergeProps } from '@destyler/svelte';
7
11
  import { runIfFn } from '@destyler/utils';
12
+ import { onDestroy, onMount, tick, untrack } from 'svelte';
8
13
  import { useFieldContext } from '../../field/index.js';
9
14
  export function useNumberInput(props) {
10
15
  const env = useEnvironmentContext();
@@ -27,11 +32,187 @@ export function useNumberInput(props) {
27
32
  ...resolvedProps,
28
33
  }, { value: 'defaultValue' });
29
34
  });
30
- const [state, send] = useMachine(() => numberInput.machine(machineProps.initial), {
35
+ let isEditingInput = $state(false);
36
+ let editingInput;
37
+ let composingValue = $state();
38
+ let composingInput;
39
+ let compositionVersion = 0;
40
+ let compositionEpoch = 0;
41
+ let disposed = false;
42
+ let cancelInputSync;
43
+ const isComposing = () => composingValue !== undefined && !!composingInput?.isConnected;
44
+ const machine = untrack(() => numberInput.machine(machineProps.initial));
45
+ const scope = createScope({});
46
+ const trackCoreFormControl = machine.options.activities?.trackFormControl;
47
+ let refreshFormControl;
48
+ machine.setOptions({
49
+ activities: {
50
+ trackFormControl(context, event, meta) {
51
+ let trackedInput;
52
+ let trackedForm;
53
+ let cleanup;
54
+ const refresh = () => {
55
+ const inputId = context.ids?.input ?? `number-input:${context.id}:input`;
56
+ const input = scope.getById(context, inputId);
57
+ const form = input?.form;
58
+ if (input === trackedInput && form === trackedForm)
59
+ return;
60
+ cleanup?.();
61
+ trackedInput = input;
62
+ trackedForm = form;
63
+ cleanup = trackCoreFormControl?.(context, event, meta) ?? undefined;
64
+ };
65
+ refreshFormControl = refresh;
66
+ refresh();
67
+ return () => {
68
+ refreshFormControl = undefined;
69
+ cleanup?.();
70
+ };
71
+ },
72
+ },
73
+ });
74
+ const [state, send] = useMachine(machine, {
31
75
  get context() {
32
76
  return machineProps.context;
33
77
  },
78
+ actions: {
79
+ syncInputElement(context, event) {
80
+ cancelInputSync?.();
81
+ if (isComposing())
82
+ return;
83
+ const inputId = context.ids?.input ?? `number-input:${context.id}:input`;
84
+ const input = scope.getById(context, inputId);
85
+ if (!input)
86
+ return;
87
+ const epoch = compositionEpoch;
88
+ const value = event.type.endsWith('CHANGE') ? context.value : context.formattedValue;
89
+ // Core queues its write in RAF. Composition can start after this action
90
+ // ran, so check ownership again at execution time, including end/blur.
91
+ cancelInputSync = syncNumberInputElement(input, value ?? '', () => !disposed && !isComposing()
92
+ && epoch === compositionEpoch && scope.getById(context, inputId) === input);
93
+ },
94
+ },
95
+ });
96
+ onDestroy(() => {
97
+ disposed = true;
98
+ cancelInputSync?.();
99
+ compositionVersion++;
100
+ });
101
+ const getInputValue = () => isComposing() ? composingValue : (state.hasTag('focus') && isEditingInput && editingInput?.isConnected ? state.context.value : state.context.formattedValue);
102
+ const syncInputValue = createInputValueSync(() => ({ value: getInputValue() }), () => state.context.value, () => !disposed && !isComposing());
103
+ const api = $derived.by(() => {
104
+ const connected = numberInput.connect(state, send, normalizeProps);
105
+ return {
106
+ ...connected,
107
+ getInputProps() {
108
+ const inputProps = connected.getInputProps();
109
+ // Core exposes a formatted defaultValue, but Svelte applies it as a
110
+ // live value. Keep the core's raw text during native editing so partial
111
+ // numbers such as "1." are not reformatted during accepted input.
112
+ return mergeProps(inputProps, {
113
+ value: getInputValue(),
114
+ oninput(event) {
115
+ // Composition is an edit too. Core 0.2.9 reconciles a rejected
116
+ // INPUT.CHANGE to raw text until blur, including IME input.
117
+ editingInput = event.currentTarget;
118
+ isEditingInput = true;
119
+ if (event.isComposing) {
120
+ if (!isComposing()) {
121
+ compositionVersion++;
122
+ compositionEpoch++;
123
+ }
124
+ composingInput = event.currentTarget;
125
+ composingValue = composingInput.value;
126
+ return;
127
+ }
128
+ // A final input event can follow compositionend in the same turn.
129
+ // Its current value supersedes any pending end reconciliation.
130
+ compositionVersion++;
131
+ composingValue = undefined;
132
+ composingInput = undefined;
133
+ void syncInputValue(event);
134
+ },
135
+ oncompositionstart(event) {
136
+ compositionEpoch++;
137
+ compositionVersion++;
138
+ composingInput = event.currentTarget;
139
+ composingValue = composingInput.value;
140
+ },
141
+ async oncompositionend(event) {
142
+ compositionEpoch++;
143
+ const input = event.currentTarget;
144
+ if (!isComposing()) {
145
+ if (input.value === state.context.value) {
146
+ editingInput = input;
147
+ isEditingInput = true;
148
+ }
149
+ else {
150
+ void syncInputValue(event);
151
+ }
152
+ return;
153
+ }
154
+ const version = compositionVersion;
155
+ const value = input.value;
156
+ const { selectionStart, selectionEnd, selectionDirection } = input;
157
+ composingValue = value;
158
+ // Keep native text through both core and bound-parent flushes.
159
+ await tick();
160
+ if (disposed || !input.isConnected || version !== compositionVersion)
161
+ return;
162
+ if (value === state.context.value) {
163
+ editingInput = input;
164
+ isEditingInput = true;
165
+ }
166
+ composingValue = undefined;
167
+ composingInput = undefined;
168
+ await tick();
169
+ if (disposed || !input.isConnected || version !== compositionVersion)
170
+ return;
171
+ if (selectionStart !== null && selectionEnd !== null)
172
+ input.setSelectionRange(selectionStart, selectionEnd, selectionDirection ?? undefined);
173
+ },
174
+ onfocusout() {
175
+ compositionEpoch++;
176
+ compositionVersion++;
177
+ composingValue = undefined;
178
+ composingInput = undefined;
179
+ editingInput = undefined;
180
+ isEditingInput = false;
181
+ },
182
+ });
183
+ },
184
+ };
185
+ });
186
+ onMount(() => {
187
+ const root = env().getRootNode();
188
+ const getInput = () => scope.getById(state.context, String(api.getInputProps().id));
189
+ const onReset = async (event) => {
190
+ // Refresh even for a different form: a moved or removed input must stop
191
+ // listening to its old form before that form's reset reaches target phase.
192
+ // Core keeps the original seed and controlled ownership callback rules.
193
+ refreshFormControl?.();
194
+ const input = getInput();
195
+ if (!input || input.form !== event.target)
196
+ return;
197
+ // The browser resets the property even when core's initial value equals
198
+ // its current value (and thus triggers no watcher). Reconcile after the
199
+ // default action and parent writeback, also ending any interrupted edit.
200
+ await tick();
201
+ if (event.defaultPrevented || disposed || !input.isConnected || input !== getInput())
202
+ return;
203
+ const version = ++compositionVersion;
204
+ compositionEpoch++;
205
+ composingValue = undefined;
206
+ composingInput = undefined;
207
+ editingInput = undefined;
208
+ isEditingInput = false;
209
+ await tick();
210
+ if (disposed || !input.isConnected || version !== compositionVersion || input !== getInput())
211
+ return;
212
+ input.value = String(getInputValue() ?? '');
213
+ };
214
+ root.addEventListener('reset', onReset, true);
215
+ return () => root.removeEventListener('reset', onReset, true);
34
216
  });
35
- const api = $derived(numberInput.connect(state, send, normalizeProps));
36
217
  return () => api;
37
218
  }
@@ -8,6 +8,7 @@
8
8
 
9
9
  <script lang="ts">
10
10
  import { mergeProps } from '@destyler/svelte'
11
+ import { createInputValueSync } from '../../../utils/sync-input-value'
11
12
  import { createSplitProps } from '../../../utils/create-split-props'
12
13
  import { UI } from '../../factory'
13
14
  import { useOtpInputContext } from '../hooks/use-otp-input-context'
@@ -17,7 +18,11 @@
17
18
 
18
19
  const [inputProps, localProps] = $derived(createSplitProps<InputProps>()(props, ['index']))
19
20
 
20
- const mergedProps = $derived(mergeProps(otpInput().getInputProps(inputProps), localProps))
21
+ const syncInputValue = createInputValueSync(() => otpInput().getInputProps(inputProps), () => otpInput().value)
22
+ const mergedProps = $derived(mergeProps(otpInput().getInputProps(inputProps), localProps, {
23
+ oninput: syncInputValue,
24
+ oncompositionend: syncInputValue,
25
+ }))
21
26
  </script>
22
27
 
23
28
  <UI as="input" {...mergedProps} />
@@ -16,7 +16,13 @@
16
16
  import { OtpInputProvider } from '../hooks/use-otp-input-context'
17
17
  import { useOtpInput } from '../hooks/use-otp-input.svelte'
18
18
 
19
- let { value = $bindable(), ...props }: OtpInputRootProps = $props()
19
+ // Read the parent prop independently from the writable binding. Local writes
20
+ // notify bind: consumers without overriding ordinary controlled props.
21
+ let {
22
+ value = $bindable(),
23
+ value: valueProp,
24
+ ...props
25
+ }: OtpInputRootProps = $props()
20
26
  const providedId = $props.id()
21
27
 
22
28
  const [useOtpInputProps, localProps] = $derived(
@@ -49,7 +55,7 @@
49
55
  const resolvedProps = $derived<UseOtpInputProps>({
50
56
  ...useOtpInputProps,
51
57
  id: useOtpInputProps.id ?? providedId,
52
- value,
58
+ value: valueProp,
53
59
  onValueChange(details) {
54
60
  useOtpInputProps.onValueChange?.(details)
55
61
  value = details.value
@@ -13,7 +13,15 @@
13
13
  import { PaginationProvider } from '../hooks/use-pagination-context'
14
14
  import { usePagination } from '../hooks/use-pagination.svelte'
15
15
 
16
- let { page = $bindable(), pageSize = $bindable(), ...props }: PaginationRootProps = $props()
16
+ // Read the parent prop independently from the writable binding. Local writes
17
+ // notify bind: consumers without overriding ordinary controlled props.
18
+ let {
19
+ page = $bindable(),
20
+ page: pageProp,
21
+ pageSize = $bindable(),
22
+ pageSize: pageSizeProp,
23
+ ...props
24
+ }: PaginationRootProps = $props()
17
25
  const providedId = $props.id()
18
26
 
19
27
  const [paginationProps, localProps] = $derived(
@@ -26,6 +34,7 @@
26
34
  'onPageSizeChange',
27
35
  'page',
28
36
  'pageSize',
37
+ 'defaultPageSize',
29
38
  'siblingCount',
30
39
  'translations',
31
40
  'type',
@@ -35,15 +44,15 @@
35
44
  const resolvedProps = $derived<UsePaginationProps>({
36
45
  ...paginationProps,
37
46
  id: paginationProps.id ?? providedId,
38
- page,
39
- pageSize,
47
+ page: pageProp,
48
+ pageSize: pageSizeProp,
40
49
  onPageChange(details) {
41
50
  paginationProps.onPageChange?.(details)
42
- if (page !== undefined) page = details.page
51
+ page = details.page
43
52
  },
44
53
  onPageSizeChange(details) {
45
54
  paginationProps.onPageSizeChange?.(details)
46
- if (pageSize !== undefined) pageSize = details.pageSize
55
+ pageSize = details.pageSize
47
56
  },
48
57
  })
49
58
 
@@ -16,7 +16,14 @@
16
16
  import { PopoverProvider } from '../hooks/use-popover-context'
17
17
  import { usePopover } from '../hooks/use-popover.svelte'
18
18
 
19
- let { open = $bindable(), children, ...props }: PopoverRootProps = $props()
19
+ // Read the parent prop independently from the writable binding. Local writes
20
+ // notify bind: consumers without overriding ordinary controlled props.
21
+ let {
22
+ open = $bindable(),
23
+ open: openProp,
24
+ children,
25
+ ...props
26
+ }: PopoverRootProps = $props()
20
27
 
21
28
  const providedId = $props.id()
22
29
 
@@ -26,10 +33,10 @@
26
33
  return {
27
34
  ...localProps,
28
35
  id: localProps.id ?? providedId,
29
- open,
36
+ open: openProp,
30
37
  onOpenChange(details) {
31
38
  localProps.onOpenChange?.(details)
32
- if (open !== undefined) open = details.open
39
+ open = details.open
33
40
  },
34
41
  }
35
42
  })
@@ -2,7 +2,7 @@ import type { Accessor } from '../../../types.js';
2
2
  import type { PropTypes } from '@destyler/svelte';
3
3
  import type { MaybeFunction } from '@destyler/utils';
4
4
  import * as popover from '@destyler/popover';
5
- export interface UsePopoverProps extends Omit<popover.Context, 'dir' | 'getRootNode' | 'open.controlled' | 'id'> {
5
+ export interface UsePopoverProps extends Omit<popover.Context, 'dir' | 'getRootNode' | 'id'> {
6
6
  id: string;
7
7
  defaultOpen?: popover.Context['open'];
8
8
  }
@@ -28,6 +28,12 @@
28
28
  ref = node
29
29
  presence().setNode(node)
30
30
  })
31
+ return () => {
32
+ untrack(() => {
33
+ if (ref === node)
34
+ ref = null
35
+ })
36
+ }
31
37
  })
32
38
  </script>
33
39
 
@@ -13,7 +13,13 @@
13
13
  import { ProgressProvider } from '../hooks/use-progress-context'
14
14
  import { useProgress } from '../hooks/use-progress.svelte'
15
15
 
16
- let { value = $bindable(), ...props }: ProgressRootProps = $props()
16
+ // Read the parent prop independently from the writable binding. Local writes
17
+ // notify bind: consumers without overriding ordinary controlled props.
18
+ let {
19
+ value = $bindable(),
20
+ value: valueProp,
21
+ ...props
22
+ }: ProgressRootProps = $props()
17
23
  const providedId = $props.id()
18
24
 
19
25
  const [useProgressProps, localProps] = $derived(
@@ -32,7 +38,7 @@
32
38
  const resolvedProps = $derived<UseProgressProps>({
33
39
  ...useProgressProps,
34
40
  id: useProgressProps.id ?? providedId,
35
- value,
41
+ value: valueProp,
36
42
  onValueChange(details) {
37
43
  value = details.value
38
44
  useProgressProps.onValueChange?.(details)
@@ -10,11 +10,25 @@ export function useProgress(props) {
10
10
  const locale = useLocaleContext();
11
11
  const machineProps = $derived.by(() => {
12
12
  const resolvedProps = runIfFn(props);
13
- return createMachineProps({
13
+ const { defaultValue, value, ...rest } = resolvedProps;
14
+ const base = {
14
15
  dir: locale().dir,
15
16
  getRootNode: env().getRootNode,
16
- ...resolvedProps,
17
- }, { value: 'defaultValue' });
17
+ ...rest,
18
+ };
19
+ // @destyler/progress@0.2.7 has no controllable defaultValue — seed initial only.
20
+ const initialValue = value !== undefined ? value : defaultValue;
21
+ const reactive = createMachineProps({
22
+ ...base,
23
+ ...(value !== undefined ? { value } : {}),
24
+ });
25
+ return {
26
+ initial: {
27
+ ...reactive.initial,
28
+ ...(initialValue !== undefined ? { value: initialValue } : {}),
29
+ },
30
+ context: reactive.context,
31
+ };
18
32
  });
19
33
  const [state, send] = useMachine(() => progress.machine(machineProps.initial), {
20
34
  get context() {
@@ -13,7 +13,13 @@
13
13
  import { QrCodeProvider } from '../hooks/use-qr-code-context'
14
14
  import { useQrCode } from '../hooks/use-qr-code.svelte'
15
15
 
16
- let { value = $bindable(), ...props }: QrCodeRootProps = $props()
16
+ // Read the parent prop independently from the writable binding. Local writes
17
+ // notify bind: consumers without overriding ordinary controlled props.
18
+ let {
19
+ value = $bindable(),
20
+ value: valueProp,
21
+ ...props
22
+ }: QrCodeRootProps = $props()
17
23
  const providedId = $props.id()
18
24
 
19
25
  const [useQrCodeProps, localProps] = $derived(
@@ -30,7 +36,7 @@
30
36
  const resolvedProps = $derived<UseQrCodeProps>({
31
37
  ...useQrCodeProps,
32
38
  id: useQrCodeProps.id ?? providedId,
33
- value,
39
+ value: valueProp,
34
40
  onValueChange(details) {
35
41
  value = details.value
36
42
  useQrCodeProps.onValueChange?.(details)
@@ -9,12 +9,22 @@ export function useQrCode(props) {
9
9
  const env = useEnvironmentContext();
10
10
  const locale = useLocaleContext();
11
11
  const machineProps = $derived.by(() => {
12
- const resolvedProps = runIfFn(props);
13
- return createMachineProps({
12
+ const { defaultValue, value, ...rest } = runIfFn(props);
13
+ const reactive = createMachineProps({
14
14
  dir: locale().dir,
15
15
  getRootNode: env().getRootNode,
16
- ...resolvedProps,
17
- }, { value: 'defaultValue' });
16
+ ...rest,
17
+ ...(value !== undefined ? { value } : {}),
18
+ });
19
+ // @destyler/qr-code@0.2.7 stores value directly — seed defaults only once.
20
+ const initialValue = value !== undefined ? value : defaultValue;
21
+ return {
22
+ initial: {
23
+ ...reactive.initial,
24
+ ...(initialValue !== undefined ? { value: initialValue } : {}),
25
+ },
26
+ context: reactive.context,
27
+ };
18
28
  });
19
29
  const [state, send] = useMachine(() => qrcode.machine(machineProps.initial), {
20
30
  get context() {
@@ -13,7 +13,13 @@
13
13
  import { RadioProvider } from '../hooks/use-radio-context'
14
14
  import { useRadio } from '../hooks/use-radio.svelte'
15
15
 
16
- let { value = $bindable(), ...props }: RadioRootProps = $props()
16
+ // Read the parent prop independently from the writable binding. Local writes
17
+ // notify bind: consumers without overriding ordinary controlled props.
18
+ let {
19
+ value = $bindable(),
20
+ value: valueProp,
21
+ ...props
22
+ }: RadioRootProps = $props()
17
23
  const providedId = $props.id()
18
24
 
19
25
  const [radioGroupProps, localProps] = $derived(
@@ -34,10 +40,10 @@
34
40
  const resolvedProps = $derived<UseRadioProps>({
35
41
  ...radioGroupProps,
36
42
  id: radioGroupProps.id ?? providedId,
37
- value,
43
+ value: valueProp,
38
44
  onValueChange(details) {
39
45
  radioGroupProps.onValueChange?.(details)
40
- if (value !== undefined) value = details.value
46
+ value = details.value
41
47
  },
42
48
  })
43
49
 
@@ -1,6 +1,8 @@
1
1
  import { useMachine } from '../../../hooks/use-destyler-machine.svelte.js';
2
2
  import { normalizeProps } from '../../../utils/normalize-props.js';
3
+ import { createRadioCheckedSync } from '../../../utils/sync-checked.js';
3
4
  import * as radio from '@destyler/radio';
5
+ import { mergeProps } from '@destyler/svelte';
4
6
  import { runIfFn } from '@destyler/utils';
5
7
  import { useEnvironmentContext, useLocaleContext } from '../../../providers/index.js';
6
8
  import { createMachineProps } from '../../../utils/create-machine-props.js';
@@ -20,6 +22,13 @@ export function useRadio(props) {
20
22
  return resolvedProps.context;
21
23
  },
22
24
  });
23
- const api = $derived(radio.connect(state, send, normalizeProps));
25
+ const connected = $derived(radio.connect(state, send, normalizeProps));
26
+ const syncChecked = createRadioCheckedSync(value => connected.getItemState({ value }).checked);
27
+ const api = $derived({
28
+ ...connected,
29
+ getItemHiddenInputProps(itemProps) {
30
+ return mergeProps(connected.getItemHiddenInputProps(itemProps), { onclick: syncChecked });
31
+ },
32
+ });
24
33
  return () => api;
25
34
  }
@@ -1,8 +1,6 @@
1
1
  import { useMachine } from '../../../hooks/use-destyler-machine.svelte.js';
2
2
  import { normalizeProps } from '../../../utils/normalize-props.js';
3
- import { resolveQueryRoot } from '../../../utils/resolve-query-root.js';
4
3
  import * as scrollArea from '@destyler/scroll-area';
5
- import { ref } from '@destyler/store';
6
4
  import { runIfFn } from '@destyler/utils';
7
5
  import { onMount } from 'svelte';
8
6
  import { useEnvironmentContext, useLocaleContext } from '../../../providers/index.js';
@@ -24,32 +22,6 @@ export function useScrollArea(props) {
24
22
  get context() {
25
23
  return machineProps;
26
24
  },
27
- actions: {
28
- // @destyler/scroll-area 0.2.6 stores ResizeObserver in proxied context.
29
- // Marking only this native instance as raw lets the core cleanup action
30
- // call disconnect() with the correct receiver.
31
- setupResizeObserver(ctx) {
32
- const rootNode = ctx.getRootNode?.() ?? env().getRootNode();
33
- const queryRoot = resolveQueryRoot(rootNode, env().getDocument());
34
- const viewportId = ctx.ids?.viewport ?? `scroll-area:${ctx.id}:viewport`;
35
- const contentId = ctx.ids?.content ?? `scroll-area:${ctx.id}:content`;
36
- const viewport = queryRoot.getElementById(viewportId);
37
- const content = queryRoot.getElementById(contentId);
38
- if (!viewport || !content)
39
- return;
40
- const updateDimensions = () => {
41
- ctx.viewportWidth = viewport.clientWidth;
42
- ctx.viewportHeight = viewport.clientHeight;
43
- ctx.contentWidth = content.scrollWidth;
44
- ctx.contentHeight = content.scrollHeight;
45
- };
46
- updateDimensions();
47
- const resizeObserver = ref(new (env().getWindow().ResizeObserver)(updateDimensions));
48
- resizeObserver.observe(viewport);
49
- resizeObserver.observe(content);
50
- ctx._resizeObserver = resizeObserver;
51
- },
52
- },
53
25
  });
54
26
  const api = $derived(scrollArea.connect(state, send, normalizeProps));
55
27
  onMount(() => {
@@ -21,9 +21,13 @@
21
21
  import { SelectProvider } from '../hooks/use-select-context'
22
22
  import { useSelect } from '../hooks/use-select.svelte'
23
23
 
24
+ // Read the parent prop independently from the writable binding. Local writes
25
+ // notify bind: consumers without overriding ordinary controlled props.
24
26
  let {
25
27
  value = $bindable<string[] | undefined>(),
28
+ value: valueProp,
26
29
  open = $bindable<boolean | undefined>(),
30
+ open: openProp,
27
31
  ...props
28
32
  }: SelectRootProps<T> = $props()
29
33
 
@@ -63,15 +67,15 @@
63
67
  const machineProps = $derived.by<UseSelectProps<T>>(() => ({
64
68
  ...useSelectProps,
65
69
  id: useSelectProps.id ?? providedId,
66
- value,
70
+ value: valueProp,
67
71
  onValueChange(details) {
68
72
  value = details.value
69
73
  useSelectProps.onValueChange?.(details)
70
74
  },
71
- open,
75
+ open: openProp,
72
76
  onOpenChange(details) {
73
77
  useSelectProps.onOpenChange?.(details)
74
- if (open !== undefined) open = details.open
78
+ open = details.open
75
79
  },
76
80
  }))
77
81
 
@@ -3,7 +3,7 @@ import type { PropTypes } from '@destyler/svelte';
3
3
  import type { MaybeFunction } from '@destyler/utils';
4
4
  import type { CollectionItem, ListCollection } from '../../collection/index.js';
5
5
  import * as select from '@destyler/select';
6
- export interface UseSelectProps<T extends CollectionItem> extends Omit<select.Context<T>, 'dir' | 'getRootNode' | 'collection' | 'open.controlled' | 'id'> {
6
+ export interface UseSelectProps<T extends CollectionItem> extends Omit<select.Context<T>, 'dir' | 'getRootNode' | 'collection' | 'id'> {
7
7
  id: string;
8
8
  defaultOpen?: select.Context<T>['open'];
9
9
  defaultValue?: select.Context<T>['value'];
@@ -13,14 +13,14 @@
13
13
 
14
14
  const props: SliderDraggingIndicatorProps = $props()
15
15
  const slider = useSliderContext()
16
- const { index } = useSliderThumbPropsContext()
17
- const mergedProps = $derived(mergeProps(slider().getDraggingIndicatorProps({ index }), props))
16
+ const thumbProps = useSliderThumbPropsContext()
17
+ const mergedProps = $derived(mergeProps(slider().getDraggingIndicatorProps(thumbProps), props))
18
18
  </script>
19
19
 
20
20
  <UI as="span" {...mergedProps}>
21
21
  {#if props.children}
22
22
  {@render props.children()}
23
23
  {:else}
24
- {slider().getThumbValue(index)}
24
+ {slider().getThumbValue(thumbProps.index)}
25
25
  {/if}
26
26
  </UI>
@@ -13,7 +13,13 @@
13
13
  import { SliderProvider } from '../hooks/use-slider-context'
14
14
  import { useSlider } from '../hooks/use-slider.svelte'
15
15
 
16
- let { value = $bindable(), ...props }: SliderRootProps = $props()
16
+ // Read the parent prop independently from the writable binding. Local writes
17
+ // notify bind: consumers without overriding ordinary controlled props.
18
+ let {
19
+ value = $bindable(),
20
+ value: valueProp,
21
+ ...props
22
+ }: SliderRootProps = $props()
17
23
  const providedId = $props.id()
18
24
 
19
25
  const [useSliderProps, localProps] = $derived(
@@ -47,7 +53,7 @@
47
53
  const resolvedProps = $derived<UseSliderProps>({
48
54
  ...useSliderProps,
49
55
  id: useSliderProps.id ?? providedId,
50
- value,
56
+ value: valueProp,
51
57
  onValueChange(details) {
52
58
  value = details.value
53
59
  useSliderProps.onValueChange?.(details)
@@ -9,11 +9,13 @@
9
9
  </script>
10
10
 
11
11
  <script lang="ts">
12
- import { untrack } from 'svelte'
13
12
  import { SliderThumbPropsProvider } from '../hooks/use-slider-thumb-props-context'
14
13
 
15
14
  const { value, children }: SliderThumbPropsProviderProps = $props()
16
- SliderThumbPropsProvider(untrack(() => value))
15
+ SliderThumbPropsProvider({
16
+ get index() { return value.index },
17
+ get name() { return value.name },
18
+ })
17
19
  </script>
18
20
 
19
21
  {@render children?.()}