@pallasoft/ps-input-components 2.1.0 → 3.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.
- package/dist/components/ps-calendar-header.js +4 -7
- package/dist/components/ps-cascader-input.js +1 -1
- package/dist/components/ps-checkbox-matrix.d.ts +13 -0
- package/dist/components/ps-checkbox-matrix.js +24 -0
- package/dist/components/ps-color-picker.js +2 -2
- package/dist/components/ps-combobox-input.js +1 -1
- package/dist/components/ps-date-input.js +1 -1
- package/dist/components/ps-date-preset-field.js +2 -2
- package/dist/components/ps-field-skeleton.js +1 -1
- package/dist/components/ps-file-picker.js +1 -1
- package/dist/components/ps-multi-select-input.js +2 -2
- package/dist/components/ps-phone-input.js +1 -1
- package/dist/components/ps-portable-text-editor.d.ts +1 -1
- package/dist/components/ps-portable-text-editor.js +1 -2
- package/dist/components/ps-portable-text-link-dialog.d.ts +2 -1
- package/dist/components/ps-portable-text-link-dialog.js +2 -2
- package/dist/components/ps-portable-text-toolbar.js +2 -7
- package/dist/components/ps-select-input.js +1 -1
- package/dist/components/ps-toggle.js +1 -1
- package/dist/components/ps-year-input.js +1 -1
- package/dist/constants/ps-calendar-header-classes.d.ts +6 -0
- package/dist/constants/ps-calendar-header-classes.js +9 -0
- package/dist/constants/ps-portable-text-editor-config.d.ts +10 -2
- package/dist/constants/ps-portable-text-editor-config.js +10 -2
- package/dist/esm/components/ps-calendar-header.js +4 -7
- package/dist/esm/components/ps-cascader-input.js +1 -1
- package/dist/esm/components/ps-checkbox-matrix.js +20 -0
- package/dist/esm/components/ps-color-picker.js +2 -2
- package/dist/esm/components/ps-combobox-input.js +1 -1
- package/dist/esm/components/ps-date-input.js +1 -1
- package/dist/esm/components/ps-date-preset-field.js +2 -2
- package/dist/esm/components/ps-field-skeleton.js +1 -1
- package/dist/esm/components/ps-file-picker.js +1 -1
- package/dist/esm/components/ps-multi-select-input.js +2 -2
- package/dist/esm/components/ps-phone-input.js +1 -1
- package/dist/esm/components/ps-portable-text-editor.js +1 -2
- package/dist/esm/components/ps-portable-text-link-dialog.js +2 -2
- package/dist/esm/components/ps-portable-text-toolbar.js +2 -7
- package/dist/esm/components/ps-select-input.js +1 -1
- package/dist/esm/components/ps-toggle.js +1 -1
- package/dist/esm/components/ps-year-input.js +1 -1
- package/dist/esm/constants/ps-calendar-header-classes.js +6 -0
- package/dist/esm/constants/ps-portable-text-editor-config.js +10 -2
- package/dist/esm/index.js +7 -0
- package/dist/esm/interfaces/ps-checkbox-matrix-cell.js +1 -0
- package/dist/esm/interfaces/ps-checkbox-matrix-column.js +1 -0
- package/dist/esm/interfaces/ps-checkbox-matrix-group.js +1 -0
- package/dist/esm/interfaces/ps-checkbox-matrix-labels.js +1 -0
- package/dist/esm/interfaces/ps-checkbox-matrix-row.js +1 -0
- package/dist/esm/portable-text-core/components/ps-portable-text-core-editor-stub.js +2 -0
- package/dist/esm/portable-text-core/components/ps-portable-text-core-editor.js +64 -0
- package/dist/esm/portable-text-core/components/ps-portable-text-core.js +5 -26
- package/dist/esm/portable-text-core/constants/ps-portable-text-core-config.js +29 -9
- package/dist/esm/portable-text-core/contexts/ps-portable-text-core-context.js +9 -0
- package/dist/esm/portable-text-core/hooks/use-ps-portable-text-link-form.js +11 -5
- package/dist/esm/portable-text-core/hooks/use-ps-portable-text-toolbar.js +17 -49
- package/dist/esm/portable-text-core/index.js +4 -0
- package/dist/esm/portable-text-core/interfaces/ps-portable-text-active-formats.js +1 -0
- package/dist/esm/portable-text-core/interfaces/ps-portable-text-block-draft.js +1 -0
- package/dist/esm/portable-text-core/interfaces/ps-portable-text-core-class-names.js +1 -0
- package/dist/esm/portable-text-core/interfaces/ps-portable-text-core-context-data.js +1 -0
- package/dist/esm/portable-text-core/interfaces/ps-portable-text-core-props.js +1 -0
- package/dist/esm/portable-text-core/interfaces/ps-portable-text-extension-options.js +1 -0
- package/dist/esm/portable-text-core/interfaces/ps-portable-text-span-draft.js +1 -0
- package/dist/esm/portable-text-core/interfaces/ps-portable-text-toolbar-state.js +1 -0
- package/dist/esm/portable-text-core/services/ps-portable-text-command-service.js +73 -0
- package/dist/esm/portable-text-core/services/ps-portable-text-converter-service.js +196 -0
- package/dist/esm/portable-text-core/services/ps-portable-text-editor-service.js +4 -0
- package/dist/esm/portable-text-core/services/ps-portable-text-extension-service.js +89 -0
- package/dist/esm/portable-text-engine/index.js +1 -0
- package/dist/esm/portable-text-engine/worker.js +1 -0
- package/dist/esm/services/ps-checkbox-matrix-service.js +28 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/interfaces/ps-checkbox-matrix-cell.d.ts +6 -0
- package/dist/interfaces/ps-checkbox-matrix-cell.js +2 -0
- package/dist/interfaces/ps-checkbox-matrix-column.d.ts +5 -0
- package/dist/interfaces/ps-checkbox-matrix-column.js +2 -0
- package/dist/interfaces/ps-checkbox-matrix-group.d.ts +6 -0
- package/dist/interfaces/ps-checkbox-matrix-group.js +2 -0
- package/dist/interfaces/ps-checkbox-matrix-labels.d.ts +9 -0
- package/dist/interfaces/ps-checkbox-matrix-labels.js +2 -0
- package/dist/interfaces/ps-checkbox-matrix-row.d.ts +6 -0
- package/dist/interfaces/ps-checkbox-matrix-row.js +2 -0
- package/dist/portable-text/index.d.ts +1 -1
- package/dist/portable-text-core/components/ps-portable-text-core-editor-stub.d.ts +2 -0
- package/dist/portable-text-core/components/ps-portable-text-core-editor-stub.js +6 -0
- package/dist/portable-text-core/components/ps-portable-text-core-editor.d.ts +2 -0
- package/dist/portable-text-core/components/ps-portable-text-core-editor.js +68 -0
- package/dist/portable-text-core/components/ps-portable-text-core.d.ts +2 -17
- package/dist/portable-text-core/components/ps-portable-text-core.js +3 -24
- package/dist/portable-text-core/constants/ps-portable-text-core-config.d.ts +36 -19
- package/dist/portable-text-core/constants/ps-portable-text-core-config.js +29 -9
- package/dist/portable-text-core/contexts/ps-portable-text-core-context.d.ts +2 -0
- package/dist/portable-text-core/contexts/ps-portable-text-core-context.js +12 -0
- package/dist/portable-text-core/hooks/use-ps-portable-text-link-form.d.ts +3 -1
- package/dist/portable-text-core/hooks/use-ps-portable-text-link-form.js +10 -4
- package/dist/portable-text-core/hooks/use-ps-portable-text-toolbar.d.ts +5 -10
- package/dist/portable-text-core/hooks/use-ps-portable-text-toolbar.js +17 -49
- package/dist/portable-text-core/index.d.ts +5 -1
- package/dist/portable-text-core/index.js +4 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-active-formats.d.ts +10 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-active-formats.js +2 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-block-draft.d.ts +7 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-block-draft.js +2 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-core-class-names.d.ts +8 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-core-class-names.js +2 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-core-context-data.d.ts +9 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-core-context-data.js +2 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-core-props.d.ts +16 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-core-props.js +2 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-editor-labels.d.ts +1 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-extension-options.d.ts +6 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-extension-options.js +2 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-span-draft.d.ts +4 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-span-draft.js +2 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-toolbar-state.d.ts +5 -0
- package/dist/portable-text-core/interfaces/ps-portable-text-toolbar-state.js +2 -0
- package/dist/portable-text-core/services/ps-portable-text-command-service.d.ts +14 -0
- package/dist/portable-text-core/services/ps-portable-text-command-service.js +77 -0
- package/dist/portable-text-core/services/ps-portable-text-converter-service.d.ts +18 -0
- package/dist/portable-text-core/services/ps-portable-text-converter-service.js +200 -0
- package/dist/portable-text-core/services/ps-portable-text-editor-service.d.ts +1 -0
- package/dist/portable-text-core/services/ps-portable-text-editor-service.js +4 -0
- package/dist/portable-text-core/services/ps-portable-text-extension-service.d.ts +8 -0
- package/dist/portable-text-core/services/ps-portable-text-extension-service.js +93 -0
- package/dist/portable-text-engine/index.d.ts +1 -0
- package/dist/portable-text-engine/index.js +17 -0
- package/dist/portable-text-engine/worker.d.ts +1 -0
- package/dist/portable-text-engine/worker.js +17 -0
- package/dist/services/ps-checkbox-matrix-service.d.ts +9 -0
- package/dist/services/ps-checkbox-matrix-service.js +32 -0
- package/package.json +30 -6
- package/dist/constants/ps-portable-text-editor-renderers.d.ts +0 -6
- package/dist/constants/ps-portable-text-editor-renderers.js +0 -32
- package/dist/esm/constants/ps-portable-text-editor-renderers.js +0 -29
|
@@ -35,7 +35,7 @@ export const PsColorPicker = ({ className, disabled, helperText, hideLabel, labe
|
|
|
35
35
|
saturation: Math.round((x / bounds.width) * 100),
|
|
36
36
|
}));
|
|
37
37
|
};
|
|
38
|
-
return (_jsxs("div", { className: PallasoftClassNameService.merge('flex flex-col gap-2', className), children: [hideLabel ? null : _jsx("span", { className: 'ps-input-label block', children: label }), _jsxs(DialogTrigger, { children: [_jsxs(Button, { "aria-label": hideLabel ? label : undefined, className: 'ps-input-control ps-focus-ring flex
|
|
38
|
+
return (_jsxs("div", { className: PallasoftClassNameService.merge('flex flex-col gap-2', className), children: [hideLabel ? null : _jsx("span", { className: 'ps-input-label block', children: label }), _jsxs(DialogTrigger, { children: [_jsxs(Button, { "aria-label": hideLabel ? label : undefined, className: 'ps-input-control ps-focus-ring flex w-full items-center gap-3 text-left text-sm font-semibold disabled:cursor-not-allowed disabled:opacity-60', isDisabled: disabled, children: [_jsx("span", { className: 'h-6 w-6 shrink-0 rounded-md border border-line', style: { backgroundColor: swatchColor ? swatchColor : 'transparent' } }), _jsx("span", { className: 'font-mono text-sm uppercase', children: swatchColor ? swatchColor : 'Pick a colour' }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'ml-auto block h-4 w-4 shrink-0 text-primary', iconKey: PsIconKey.Chevron })] }), _jsx(Popover, { className: 'ps-floating-panel w-[min(calc(100vw-2rem),18rem)] outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsxs(Dialog, { "aria-label": label, className: 'flex flex-col gap-3 p-3 outline-none', children: [_jsx("div", { className: 'relative h-36 w-full cursor-crosshair rounded-ps-control', onPointerDown: (event) => {
|
|
39
39
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
40
40
|
pickFromArea(event);
|
|
41
41
|
}, onPointerMove: (event) => {
|
|
@@ -49,7 +49,7 @@ export const PsColorPicker = ({ className, disabled, helperText, hideLabel, labe
|
|
|
49
49
|
backgroundColor: swatchColor ? swatchColor : 'transparent',
|
|
50
50
|
} }) }), _jsxs("label", { className: 'flex flex-col gap-1', children: [_jsx("span", { className: 'ps-input-helper', children: "Hue" }), _jsx("input", { className: 'ps-focus-ring h-3 w-full cursor-pointer appearance-none rounded-full', max: 360, min: 0, onChange: (event) => onChange(PsColorService.toHex({ ...hsv, hue: Number(event.target.value) })), step: 1, style: {
|
|
51
51
|
background: 'linear-gradient(to right, #FF0000, #FFFF00, #00FF00, #00FFFF, #0000FF, #FF00FF, #FF0000)',
|
|
52
|
-
}, type: 'range', value: hsv.hue })] }), _jsx("input", { "aria-label": `${label} hex`, className: 'ps-input-control ps-focus-ring
|
|
52
|
+
}, type: 'range', value: hsv.hue })] }), _jsx("input", { "aria-label": `${label} hex`, className: 'ps-input-control ps-control-compact ps-focus-ring w-full font-mono text-sm uppercase', maxLength: 7, onBlur: (event) => commitHex(event.target.value), onChange: (event) => setDraft(event.target.value), onKeyDown: (event) => {
|
|
53
53
|
if (event.key !== 'Enter')
|
|
54
54
|
return;
|
|
55
55
|
event.preventDefault();
|
|
@@ -6,5 +6,5 @@ import { PsComboboxInputService } from '../services/ps-combobox-input-service';
|
|
|
6
6
|
import { PsRequiredMark } from './ps-required-mark';
|
|
7
7
|
export const PsComboboxInput = ({ className, emptyText, getItemKey, getItemLabel, hideLabel = false, inputValue, isLoading = false, items, label, onInputChange, onSelectionChange, placeholder, renderItem, required, selectedKey, }) => {
|
|
8
8
|
const itemsByKey = new Map(items.map((item) => [getItemKey(item), item]));
|
|
9
|
-
return (_jsxs(ComboBox, { allowsEmptyCollection: true, "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), defaultFilter: () => true, inputValue: inputValue, items: items, onInputChange: onInputChange, selectedKey: selectedKey, onSelectionChange: (key) => onSelectionChange?.(key === null ? null : PsComboboxInputService.getItem(itemsByKey, key)), children: [label && !hideLabel ? (_jsxs(Label, { className: 'ps-input-label', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })) : null, _jsx("span", { className: hideLabel || !label ? 'relative block' : 'relative mt-2 block', children: _jsx(Input, { className: 'ps-input-control ps-focus-ring
|
|
9
|
+
return (_jsxs(ComboBox, { allowsEmptyCollection: true, "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), defaultFilter: () => true, inputValue: inputValue, items: items, onInputChange: onInputChange, selectedKey: selectedKey, onSelectionChange: (key) => onSelectionChange?.(key === null ? null : PsComboboxInputService.getItem(itemsByKey, key)), children: [label && !hideLabel ? (_jsxs(Label, { className: 'ps-input-label', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })) : null, _jsx("span", { className: hideLabel || !label ? 'relative block' : 'relative mt-2 block', children: _jsx(Input, { className: 'ps-input-control ps-focus-ring w-full text-sm font-semibold', placeholder: placeholder }) }), _jsx(Popover, { className: 'w-[--trigger-width] rounded-2xl border border-line bg-white/95 p-1.5 shadow-lg dark:border-white/10 dark:bg-slate-900/95', children: isLoading ? (_jsx("div", { className: 'flex items-center justify-center py-4', children: _jsx(PsSpinner, { label: 'Loading results', size: 'small' }) })) : (_jsx(ListBox, { className: 'max-h-72 overflow-y-auto outline-none', items: items, renderEmptyState: () => emptyText ? _jsx("div", { className: 'px-3 py-2 text-sm text-ink/55', children: emptyText }) : null, children: (item) => (_jsx(ListBoxItem, { className: 'ps-focus-ring cursor-pointer rounded-ps-control px-3 py-2 text-sm font-semibold text-ink selected:bg-primary-soft selected:text-primary hover:bg-slate-50 dark:hover:bg-white/6', id: getItemKey(item), textValue: getItemLabel(item), children: renderItem ? renderItem(item) : getItemLabel(item) })) })) })] }));
|
|
10
10
|
};
|
|
@@ -38,5 +38,5 @@ export const PsDateInput = ({ className, defaultValue, disabled, helperText, hid
|
|
|
38
38
|
setUncontrolledValue(nextValue);
|
|
39
39
|
onChange?.(nextValue);
|
|
40
40
|
};
|
|
41
|
-
return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label block', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: hideLabel ? 'relative' : 'relative mt-2', children: [_jsx(DatePicker, { autoComplete: 'off', calendarClassName: PallasoftClassNameService.merge('ps-floating-panel ps-datepicker', view === PsCalendarView.day ? undefined : PsDateInputConfig.pickingClassName), className: 'ps-input-control ps-focus-ring
|
|
41
|
+
return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label block', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: hideLabel ? 'relative' : 'relative mt-2', children: [_jsx(DatePicker, { autoComplete: 'off', calendarClassName: PallasoftClassNameService.merge('ps-floating-panel ps-datepicker', view === PsCalendarView.day ? undefined : PsDateInputConfig.pickingClassName), className: 'ps-input-control ps-focus-ring w-full pr-10 text-sm font-semibold', dateFormat: [...PsDateInputConfig.inputFormats], disabled: disabled, id: inputId, maxDate: maxDate, minDate: minDate, onCalendarClose: () => setView(PsCalendarView.day), onChange: handleChange, placeholderText: placeholder, popperClassName: 'ps-datepicker-popper', popperPlacement: 'bottom-start', popperProps: { strategy: 'fixed' }, portalId: portalId, renderCustomHeader: (headerProps) => (_jsx(PsCalendarHeader, { ...headerProps, maxDate: maxDate, minDate: minDate, onViewChange: setView, view: view })), required: required, selected: PsDateInputService.parse(currentValue), showPopperArrow: false, wrapperClassName: 'block w-full' }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-ink/50', iconKey: PsIconKey.Calendar }), name ? _jsx("input", { name: name, type: 'hidden', value: currentValue }) : null] }), helperText ? _jsx("span", { className: 'ps-input-helper', children: helperText }) : null] }));
|
|
42
42
|
};
|
|
@@ -2,5 +2,5 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { PsDateInput } from './ps-date-input';
|
|
3
3
|
import { PsFormControl } from './ps-form-control';
|
|
4
4
|
export const PsDatePresetField = ({ errorText, hideLabel, label, onChange, presets, presetsDisabled = false, presetsLabel, required, value, }) => (_jsxs("div", { className: 'flex flex-col gap-2', children: [_jsx(PsFormControl, { errorText: errorText, children: _jsx(PsDateInput, { hideLabel: hideLabel, label: label, onChange: onChange, required: required, value: value }) }), _jsx("div", { "aria-label": presetsLabel, className: 'flex flex-wrap gap-1.5', role: 'group', children: presets.map((preset) => (_jsx("button", { "aria-pressed": preset.date !== '' && preset.date === value, className: preset.date !== '' && preset.date === value
|
|
5
|
-
? 'ps-focus-ring rounded-
|
|
6
|
-
: 'ps-focus-ring rounded-
|
|
5
|
+
? 'ps-focus-ring rounded-ps-control bg-primary px-2.5 py-1 text-xs font-semibold text-white'
|
|
6
|
+
: 'ps-focus-ring rounded-ps-control border border-line px-2.5 py-1 text-xs font-medium text-ink/70 hover:border-primary/40 hover:text-ink disabled:opacity-40', disabled: presetsDisabled, onClick: () => onChange(preset.date), type: 'button', children: preset.label }, preset.label))) })] }));
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
3
|
-
export const PsFieldSkeleton = ({ className, hideLabel, label, rows = 1, }) => (_jsxs("div", { "aria-busy": 'true', className: 'block', role: 'status', children: [_jsx("span", { className: 'sr-only', children: label }), hideLabel ? null : _jsx("span", { className: 'ps-skeleton mb-2 block h-2.5 w-24 rounded-full' }), _jsx("span", { className: PallasoftClassNameService.merge('ps-skeleton block w-full rounded-ps-control', rows > 1 ? 'min-h-24' : 'min-h-
|
|
3
|
+
export const PsFieldSkeleton = ({ className, hideLabel, label, rows = 1, }) => (_jsxs("div", { "aria-busy": 'true', className: 'block', role: 'status', children: [_jsx("span", { className: 'sr-only', children: label }), hideLabel ? null : _jsx("span", { className: 'ps-skeleton mb-2 block h-2.5 w-24 rounded-full' }), _jsx("span", { className: PallasoftClassNameService.merge('ps-skeleton block w-full rounded-ps-control', rows > 1 ? 'min-h-24' : 'min-h-ps-control', className) })] }));
|
|
@@ -25,5 +25,5 @@ export const PsFilePicker = ({ accept, acceptLabel, className, disabled, dropLab
|
|
|
25
25
|
}
|
|
26
26
|
onFileLoad(newFile);
|
|
27
27
|
};
|
|
28
|
-
return (_jsxs("div", { className: PallasoftClassNameService.merge('relative flex h-48 w-full flex-col items-center justify-center rounded-
|
|
28
|
+
return (_jsxs("div", { className: PallasoftClassNameService.merge('relative flex h-48 w-full flex-col items-center justify-center rounded-ps-control border-2 border-dashed border-line p-4 transition-all hover:border-primary/50 hover:bg-primary/5 sm:h-64', className), children: [_jsxs("div", { className: 'flex flex-col items-center gap-3 text-center', children: [_jsx(PsIcon, { iconKey: 'upload', className: 'h-8 w-8 text-primary' }), _jsxs("div", { children: [_jsx("p", { className: 'text-body-2 font-medium text-ink sm:text-body-1', children: dropLabel }), _jsx("p", { className: 'mt-1 text-body-3 text-ink/60 sm:text-body-2', children: "or click to browse your files" }), maxSizeLabel ? _jsx("p", { className: 'mt-3 text-body-3 text-ink/60', children: maxSizeLabel }) : null, _jsxs("p", { className: 'text-body-3 text-ink/60', children: ["Accepted formats: ", acceptLabel] })] })] }), _jsx("input", { type: 'file', accept: acceptAttr, className: 'absolute inset-0 h-full w-full cursor-pointer opacity-0', "aria-label": 'File upload', onChange: onFileChange, disabled: disabled, "aria-disabled": disabled })] }));
|
|
29
29
|
};
|
|
@@ -20,7 +20,7 @@ export const PsMultiSelectInput = ({ className, defaultValue, disabled, helperTe
|
|
|
20
20
|
setUncontrolledValue(nextValue);
|
|
21
21
|
onChange?.(nextValue);
|
|
22
22
|
};
|
|
23
|
-
return (_jsxs(Select, { "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), isDisabled: disabled, isRequired: required, name: name, onChange: handleChange, placeholder: placeholder, selectionMode: 'multiple', value: currentValue.filter((selected) => labelByValue.has(selected)), children: [hideLabel ? null : (_jsxs(Label, { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(Button, { className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex
|
|
23
|
+
return (_jsxs(Select, { "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), isDisabled: disabled, isRequired: required, name: name, onChange: handleChange, placeholder: placeholder, selectionMode: 'multiple', value: currentValue.filter((selected) => labelByValue.has(selected)), children: [hideLabel ? null : (_jsxs(Label, { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(Button, { className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex w-full items-center py-1.5 pr-10 text-left text-sm font-semibold disabled:cursor-not-allowed disabled:opacity-60', hideLabel ? '' : 'mt-2'), children: [_jsx(SelectValue, { className: 'flex min-w-0 flex-1 flex-wrap gap-1.5', children: ({ isPlaceholder }) => isPlaceholder ? (_jsx("span", { className: 'font-medium text-ink/45', children: placeholder })) : (currentValue
|
|
24
24
|
.filter((selected) => labelByValue.has(selected))
|
|
25
|
-
.map((selected) => (_jsx("span", { className: 'inline-flex max-w-full items-center rounded-
|
|
25
|
+
.map((selected) => (_jsx("span", { className: 'inline-flex max-w-full items-center rounded-ps-control bg-primary/12 px-2.5 py-0.5 text-xs font-semibold text-ink', children: _jsx("span", { className: 'truncate', children: labelByValue.get(selected) }) }, selected)))) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), helperText ? (_jsx(Text, { className: 'ps-input-helper', slot: 'description', children: helperText })) : null, _jsx(Popover, { className: 'ps-floating-panel ps-scrollbar-hidden max-h-72 min-w-[var(--trigger-width)] overflow-y-auto p-1.5 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(ListBox, { className: 'outline-none', items: options.map((option) => ({ ...option, id: option.value })), children: (option) => _jsx(PsSelectOptionItem, { option: option }) }) })] }));
|
|
26
26
|
};
|
|
@@ -34,7 +34,7 @@ export const PsPhoneInput = ({ className, defaultCountry = PsPhoneInputConfig.de
|
|
|
34
34
|
emit(national, code);
|
|
35
35
|
document.getElementById(inputId)?.focus();
|
|
36
36
|
};
|
|
37
|
-
return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: PallasoftClassNameService.merge('ps-input-control flex
|
|
37
|
+
return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: PallasoftClassNameService.merge('ps-input-control flex items-stretch overflow-hidden p-0 focus-within:border-primary has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-primary', hideLabel ? '' : 'mt-2', isInvalid ? 'border-danger bg-danger/5' : '', disabled ? 'opacity-60' : ''), children: [_jsxs(DialogTrigger, { isOpen: isOpen, onOpenChange: setIsOpen, children: [_jsxs(Button, { "aria-label": PsPhoneInputConfig.countryLabel, className: 'flex shrink-0 items-center gap-1.5 border-r border-line px-3 outline-none focus-visible:bg-primary/10 text-sm font-semibold text-ink', isDisabled: disabled, children: [country, _jsx(PsIcon, { "aria-hidden": 'true', className: 'block h-3.5 w-3.5 text-ink/45', iconKey: PsIconKey.Chevron })] }), _jsx(Popover, { className: 'ps-floating-panel w-72 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsxs(Dialog, { "aria-label": PsPhoneInputConfig.countryLabel, className: 'flex flex-col outline-none', children: [_jsx("div", { className: 'border-b border-line p-2', children: _jsx("input", { "aria-label": PsPhoneInputConfig.searchPlaceholder, autoFocus: true, className: 'ps-input-control ps-control-compact ps-focus-ring w-full text-sm', onChange: (event) => setQuery(event.target.value), placeholder: PsPhoneInputConfig.searchPlaceholder, type: 'search', value: query }) }), _jsx("ul", { className: 'ps-scrollbar-hidden max-h-64 overflow-y-auto p-1.5', role: 'listbox', children: matches.length === 0 ? (_jsx("li", { className: 'px-3 py-2.5 text-sm text-ink/50', children: PsPhoneInputConfig.emptyMessage })) : (matches.map((option) => (_jsx("li", { role: 'none', children: _jsxs("button", { "aria-selected": option.code === country, className: PallasoftClassNameService.merge('ps-focus-ring flex w-full items-center justify-between gap-3 rounded-ps-control px-3 py-2.5 text-left text-sm', option.code === country
|
|
38
38
|
? 'bg-primary/10 text-ink'
|
|
39
39
|
: 'text-ink/80 hover:bg-mist/60 hover:text-ink'), onClick: () => choose(option.code), role: 'option', type: 'button', children: [_jsx("span", { className: 'min-w-0 truncate', children: PsPhoneInputService.highlight(option.label, query).map((part, index) => part.isMatch ? (_jsx("strong", { className: 'font-semibold text-ink', children: part.text }, index)) : (_jsx("span", { children: part.text }, index))) }), _jsxs("span", { className: 'shrink-0 text-xs text-ink/50', children: ["+", option.callingCode] })] }) }, option.code)))) })] }) })] }), _jsxs("span", { "aria-hidden": 'true', className: 'flex items-center pl-3 text-sm text-ink/45', children: [PsPhoneInputConfig.plus, PsPhoneInputService.callingCode(country)] }), _jsx("input", { "aria-invalid": isInvalid, autoComplete: 'tel-national', className: 'min-w-0 flex-1 bg-transparent px-2 text-sm text-ink outline-none', disabled: disabled, id: inputId, inputMode: 'tel', name: name, onBlur: () => {
|
|
40
40
|
setIsTouched(true);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
3
3
|
import { PsPortableTextEditorConfig } from '../constants/ps-portable-text-editor-config';
|
|
4
|
-
import { PsPortableTextEditorRenderers } from '../constants/ps-portable-text-editor-renderers';
|
|
5
4
|
import { PsPortableTextCore } from '../portable-text-core/components/ps-portable-text-core';
|
|
6
5
|
import { PsPortableTextCoreConfig } from '../portable-text-core/constants/ps-portable-text-core-config';
|
|
7
6
|
import { PsPortableTextEditorService } from '../portable-text-core/services/ps-portable-text-editor-service';
|
|
8
7
|
import { PsPortableTextToolbar } from './ps-portable-text-toolbar';
|
|
9
|
-
export const PsPortableTextEditor = ({ className, disabled = false, labels = PsPortableTextCoreConfig.labels, minRows = 4, onChange, placeholder, value, }) => (_jsx(PsPortableTextCore, {
|
|
8
|
+
export const PsPortableTextEditor = ({ className, disabled = false, labels = PsPortableTextCoreConfig.labels, minRows = 4, onChange, placeholder, value, }) => (_jsx(PsPortableTextCore, { className: PallasoftClassNameService.merge(PsPortableTextEditorConfig.classNames.root, className), classNames: PsPortableTextEditorConfig.contentClassNames, disabled: disabled, editableClassName: PsPortableTextEditorConfig.classNames.editable, fallback: _jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": 'true', className: PsPortableTextEditorConfig.classNames.toolbar, children: _jsx("span", { className: 'h-9' }) }), _jsx("div", { "aria-hidden": 'true', className: PsPortableTextEditorConfig.classNames.editable, style: { minHeight: PsPortableTextEditorService.minHeight(minRows) } })] }), label: labels.editor, minRows: minRows, onChange: onChange, placeholder: placeholder, toolbar: _jsx(PsPortableTextToolbar, { disabled: disabled, labels: labels }), value: value }));
|
|
@@ -3,7 +3,7 @@ import { PsFormModal } from '@pallasoft/ps-popovers';
|
|
|
3
3
|
import { PsPortableTextCoreConfig } from '../portable-text-core/constants/ps-portable-text-core-config';
|
|
4
4
|
import { usePsPortableTextLinkForm } from '../portable-text-core/hooks/use-ps-portable-text-link-form';
|
|
5
5
|
import { PsUrlInput } from './ps-url-input';
|
|
6
|
-
export const PsPortableTextLinkDialog = ({ isOpen, labels, onClose, onSubmit, }) => {
|
|
7
|
-
const form = usePsPortableTextLinkForm({ onClose, onSubmit });
|
|
6
|
+
export const PsPortableTextLinkDialog = ({ href, isOpen, labels, onClose, onSubmit, }) => {
|
|
7
|
+
const form = usePsPortableTextLinkForm({ href, isOpen, onClose, onSubmit });
|
|
8
8
|
return (_jsx(PsFormModal, { cancelLabel: labels.cancel, isOpen: isOpen, isSubmitDisabled: form.isSubmitDisabled, onClose: form.close, onSubmit: form.submit, size: 'sm', submitLabel: labels.saveLink, title: labels.linkDialogTitle, children: _jsx(PsUrlInput, { "aria-invalid": form.hasError, autoFocus: true, helperText: form.hasError ? labels.invalidLink : undefined, label: labels.linkUrl, name: PsPortableTextCoreConfig.linkAnnotation, onChange: (event) => form.setAddress(event.target.value), value: form.address }) }));
|
|
9
9
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
2
|
import { PsPortableTextEditorConfig } from '../constants/ps-portable-text-editor-config';
|
|
4
3
|
import { PsPortableTextCoreConfig } from '../portable-text-core/constants/ps-portable-text-core-config';
|
|
5
4
|
import { usePsPortableTextToolbar } from '../portable-text-core/hooks/use-ps-portable-text-toolbar';
|
|
@@ -7,12 +6,8 @@ import { PsPortableTextLinkDialog } from './ps-portable-text-link-dialog';
|
|
|
7
6
|
import { PsPortableTextToolbarButton } from './ps-portable-text-toolbar-button';
|
|
8
7
|
export const PsPortableTextToolbar = ({ disabled, labels }) => {
|
|
9
8
|
const toolbar = usePsPortableTextToolbar();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
setIsLinkOpen(false);
|
|
13
|
-
toolbar.focus();
|
|
14
|
-
}, onSubmit: (href) => {
|
|
9
|
+
return (_jsxs("div", { "aria-label": labels.toolbar, className: PsPortableTextEditorConfig.classNames.toolbar, role: 'toolbar', children: [_jsx(PsPortableTextToolbarButton, { className: 'font-bold', disabled: disabled, isActive: toolbar.active.bold, label: labels.bold, onClick: () => toolbar.toggleDecorator(PsPortableTextCoreConfig.decorators.bold), children: "B" }), _jsx(PsPortableTextToolbarButton, { className: 'italic', disabled: disabled, isActive: toolbar.active.italic, label: labels.italic, onClick: () => toolbar.toggleDecorator(PsPortableTextCoreConfig.decorators.italic), children: "I" }), _jsx(PsPortableTextToolbarButton, { className: 'underline', disabled: disabled, isActive: toolbar.active.underline, label: labels.underline, onClick: () => toolbar.toggleDecorator(PsPortableTextCoreConfig.decorators.underline), children: "U" }), _jsx(PsPortableTextToolbarButton, { className: 'font-mono', disabled: disabled, isActive: toolbar.active.code, label: labels.code, onClick: () => toolbar.toggleDecorator(PsPortableTextCoreConfig.decorators.code), children: '</>' }), _jsx(PsPortableTextToolbarButton, { disabled: disabled, isActive: toolbar.active.link, label: toolbar.active.link ? labels.removeLink : labels.link, onClick: () => (toolbar.active.link ? toolbar.removeLink() : toolbar.openLink()), children: _jsx("span", { className: 'underline', children: labels.link }) }), _jsx(PsPortableTextLinkDialog, { href: toolbar.linkHref, isOpen: toolbar.isLinkOpen, labels: labels, onClose: toolbar.closeLink, onSubmit: (href) => {
|
|
10
|
+
toolbar.closeLink();
|
|
15
11
|
toolbar.addLink(href);
|
|
16
|
-
setIsLinkOpen(false);
|
|
17
12
|
} }), _jsx("span", { "aria-hidden": 'true', className: PsPortableTextEditorConfig.classNames.separator }), _jsx(PsPortableTextToolbarButton, { disabled: disabled, isActive: toolbar.active.bulletedList, label: labels.bulletedList, onClick: () => toolbar.toggleListItem(PsPortableTextCoreConfig.listItems.bullet), children: "\u2022" }), _jsx(PsPortableTextToolbarButton, { disabled: disabled, isActive: toolbar.active.numberedList, label: labels.numberedList, onClick: () => toolbar.toggleListItem(PsPortableTextCoreConfig.listItems.number), children: "1." }), _jsx(PsPortableTextToolbarButton, { disabled: disabled, isActive: toolbar.active.quote, label: labels.quote, onClick: toolbar.toggleQuote, children: "\u201D" })] }));
|
|
18
13
|
};
|
|
@@ -21,5 +21,5 @@ export const PsSelectInput = ({ className, defaultValue, disabled, helperText, h
|
|
|
21
21
|
setUncontrolledValue(nextValue);
|
|
22
22
|
onChange?.(nextValue);
|
|
23
23
|
};
|
|
24
|
-
return (_jsxs(Select, { "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), isDisabled: disabled, isRequired: required, name: name, onChange: handleChange, placeholder: placeholder, value: hasOption ? currentValue : null, children: [hideLabel ? null : (_jsxs(Label, { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(Button, { className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex
|
|
24
|
+
return (_jsxs(Select, { "aria-label": hideLabel ? label : undefined, className: PallasoftClassNameService.merge('block', className), isDisabled: disabled, isRequired: required, name: name, onChange: handleChange, placeholder: placeholder, value: hasOption ? currentValue : null, children: [hideLabel ? null : (_jsxs(Label, { className: 'ps-input-label block', children: [label, _jsx(PsRequiredMark, { isRequired: required })] })), _jsxs(Button, { className: PallasoftClassNameService.merge('ps-input-control ps-focus-ring relative flex w-full items-center pr-10 text-left text-sm font-semibold disabled:cursor-not-allowed disabled:opacity-60', hideLabel ? '' : 'mt-2'), children: [_jsx(SelectValue, { className: 'min-w-0 flex-1 truncate', children: ({ isPlaceholder, selectedText }) => isPlaceholder ? (_jsx("span", { className: 'font-medium text-ink/45', children: placeholder })) : (selectedText) }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-primary', iconKey: PsIconKey.Chevron })] }), helperText ? (_jsx(Text, { className: 'ps-input-helper', slot: 'description', children: helperText })) : null, _jsx(Popover, { className: 'ps-floating-panel ps-scrollbar-hidden max-h-72 min-w-[var(--trigger-width)] overflow-y-auto p-1.5 outline-none', offset: 6, placement: 'bottom start', style: { zIndex }, children: _jsx(ListBox, { className: 'outline-none', items: options.map((option) => ({ ...option, id: option.value })), children: (option) => _jsx(PsSelectOptionItem, { option: option }) }) })] }));
|
|
25
25
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
3
|
-
export const PsToggle = ({ description, isChecked, label, name, onChange }) => (_jsxs("label", { className: 'ps-
|
|
3
|
+
export const PsToggle = ({ description, isChecked, label, name, onChange }) => (_jsxs("label", { className: 'ps-control flex cursor-pointer items-center justify-between gap-4 rounded-ps-control border border-line bg-white/78 px-4 py-3 has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-primary text-ink transition-colors hover:border-primary/35 dark:border-white/10 dark:bg-white/6 dark:text-white', children: [_jsxs("span", { children: [_jsx("span", { className: 'block text-sm font-semibold text-current', children: label }), description ? (_jsx("span", { className: 'mt-1 block text-xs leading-5 text-slate-500 dark:text-slate-400', children: description })) : null] }), _jsx("input", { checked: isChecked, className: 'sr-only', name: name, onChange: (event) => onChange?.(event.target.checked), type: 'checkbox' }), _jsx("span", { className: PallasoftClassNameService.merge('flex h-7 w-12 items-center rounded-full p-1 transition', isChecked ? 'bg-primary' : 'bg-slate-200 dark:bg-slate-700'), children: _jsx("span", { className: PallasoftClassNameService.merge('h-5 w-5 rounded-full bg-white ring-1 ring-black/5 transition dark:ring-white/10', isChecked && 'translate-x-5') }) })] }));
|
|
@@ -40,7 +40,7 @@ export const PsYearInput = ({ className, defaultValue, disabled, helperText, hid
|
|
|
40
40
|
setUncontrolledValue(nextValue);
|
|
41
41
|
onChange?.(nextValue);
|
|
42
42
|
};
|
|
43
|
-
return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label block', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: hideLabel ? 'relative' : 'relative mt-2', children: [_jsx(DatePicker, { autoComplete: 'off', calendarClassName: `ps-floating-panel ps-datepicker ${PsDateInputConfig.pickingClassName}`, className: 'ps-input-control ps-focus-ring
|
|
43
|
+
return (_jsxs("div", { className: PallasoftClassNameService.merge('block', className), children: [_jsxs("label", { className: hideLabel ? 'sr-only' : 'ps-input-label block', htmlFor: inputId, children: [label, _jsx(PsRequiredMark, { isRequired: required })] }), _jsxs("div", { className: hideLabel ? 'relative' : 'relative mt-2', children: [_jsx(DatePicker, { autoComplete: 'off', calendarClassName: `ps-floating-panel ps-datepicker ${PsDateInputConfig.pickingClassName}`, className: 'ps-input-control ps-focus-ring w-full pr-10 text-sm font-semibold', dateFormat: PsYearInputConfig.format, disabled: disabled, id: inputId, maxDate: maxDate, minDate: minDate, onChange: handleChange, placeholderText: placeholder, popperClassName: 'ps-datepicker-popper', popperPlacement: 'bottom-start', popperProps: { strategy: 'fixed' }, portalId: portalId, ref: pickerRef, renderCustomHeader: (headerProps) => (_jsx(PsCalendarHeader, { ...headerProps, maxDate: maxDate, minDate: minDate, onViewChange: () => undefined, onYearPick: (year) => {
|
|
44
44
|
handleChange(PsYearInputService.startOfYear(year));
|
|
45
45
|
pickerRef.current?.setOpen(false);
|
|
46
46
|
}, selectedYear: selected === null ? undefined : selected.getFullYear(), view: PsCalendarView.year })), required: required, selected: selected, showPopperArrow: false, wrapperClassName: 'block w-full' }), _jsx(PsIcon, { "aria-hidden": 'true', className: 'pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2 text-ink/50', iconKey: PsIconKey.Calendar }), name ? _jsx("input", { name: name, type: 'hidden', value: currentValue }) : null] }), helperText ? _jsx("span", { className: 'ps-input-helper', children: helperText }) : null] }));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const PsCalendarHeaderClasses = {
|
|
2
|
+
navigationButton: 'ps-focus-ring ps-control-square ps-control-compact flex items-center justify-center rounded-ps-control text-ink/60 transition-colors hover:bg-primary/10 hover:text-ink disabled:cursor-not-allowed disabled:opacity-30',
|
|
3
|
+
titleButton: 'ps-focus-ring ps-control-compact ps-control-padding-compact flex items-center gap-1 rounded-ps-control text-sm font-semibold text-ink transition-colors hover:bg-primary/10',
|
|
4
|
+
cell: 'ps-focus-ring ps-control flex items-center justify-center rounded-ps-control text-sm font-medium text-ink transition-colors hover:bg-primary/10 disabled:cursor-not-allowed disabled:opacity-35 disabled:hover:bg-transparent',
|
|
5
|
+
selectedCell: 'bg-primary font-bold text-[var(--ps-color-primary-contrast)] hover:bg-primary',
|
|
6
|
+
};
|
|
@@ -2,9 +2,17 @@ export const PsPortableTextEditorConfig = {
|
|
|
2
2
|
classNames: {
|
|
3
3
|
editable: 'ps-input-control w-full resize-none overflow-y-auto rounded-t-none border-t-0 leading-6 outline-none',
|
|
4
4
|
root: 'block',
|
|
5
|
-
toolbar: 'flex flex-wrap items-center gap-1 rounded-t-
|
|
6
|
-
button: 'ps-focus-ring inline-flex
|
|
5
|
+
toolbar: 'flex flex-wrap items-center gap-1 rounded-t-ps-control border border-line bg-white p-1 dark:bg-transparent',
|
|
6
|
+
button: 'ps-focus-ring ps-control-compact inline-flex min-w-ps-control-compact items-center justify-center rounded-ps-control px-2 text-sm text-ink/70 transition-colors hover:bg-ink/5 hover:text-ink disabled:cursor-not-allowed disabled:opacity-40',
|
|
7
7
|
buttonActive: 'bg-primary text-white hover:bg-primary hover:text-white',
|
|
8
8
|
separator: 'mx-1 h-5 w-px bg-line',
|
|
9
9
|
},
|
|
10
|
+
contentClassNames: {
|
|
11
|
+
blockquote: 'border-l-2 border-primary pl-3 text-ink/80',
|
|
12
|
+
bulletList: 'list-disc pl-6',
|
|
13
|
+
code: 'rounded bg-ink/10 px-1 font-mono text-[0.9em]',
|
|
14
|
+
link: 'text-primary underline',
|
|
15
|
+
orderedList: 'list-decimal pl-6',
|
|
16
|
+
placeholder: 'before:pointer-events-none before:float-left before:h-0 before:text-ink/45 before:content-[attr(data-placeholder)]',
|
|
17
|
+
},
|
|
10
18
|
};
|
package/dist/esm/index.js
CHANGED
|
@@ -47,3 +47,10 @@ export * from './constants/ps-select-with-create-config';
|
|
|
47
47
|
export * from './interfaces/ps-date-preset-data';
|
|
48
48
|
export * from './components/ps-option-card-group';
|
|
49
49
|
export * from './interfaces/ps-option-card-data';
|
|
50
|
+
export * from './components/ps-checkbox-matrix';
|
|
51
|
+
export * from './interfaces/ps-checkbox-matrix-cell';
|
|
52
|
+
export * from './interfaces/ps-checkbox-matrix-column';
|
|
53
|
+
export * from './interfaces/ps-checkbox-matrix-group';
|
|
54
|
+
export * from './interfaces/ps-checkbox-matrix-labels';
|
|
55
|
+
export * from './interfaces/ps-checkbox-matrix-row';
|
|
56
|
+
export * from './services/ps-checkbox-matrix-service';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { EditorContent, useEditor, useEditorState } from '@tiptap/react';
|
|
4
|
+
import { PsPortableTextCoreContext } from '../contexts/ps-portable-text-core-context';
|
|
5
|
+
import { PsPortableTextCommandService } from '../services/ps-portable-text-command-service';
|
|
6
|
+
import { PsPortableTextConverterService } from '../services/ps-portable-text-converter-service';
|
|
7
|
+
import { PsPortableTextEditorService } from '../services/ps-portable-text-editor-service';
|
|
8
|
+
import { PsPortableTextExtensionService } from '../services/ps-portable-text-extension-service';
|
|
9
|
+
export const PsPortableTextCoreEditor = ({ className, classNames, disabled = false, editableClassName = '', label, minRows = 4, onChange, placeholder = '', toolbar, value, }) => {
|
|
10
|
+
const [isLinkOpen, setIsLinkOpen] = useState(false);
|
|
11
|
+
const lastValue = useRef(value);
|
|
12
|
+
const editor = useEditor({
|
|
13
|
+
content: PsPortableTextConverterService.toDocument(value),
|
|
14
|
+
editable: !disabled,
|
|
15
|
+
editorProps: {
|
|
16
|
+
attributes: {
|
|
17
|
+
...(label === undefined ? {} : { 'aria-label': label }),
|
|
18
|
+
'aria-multiline': 'true',
|
|
19
|
+
'class': editableClassName,
|
|
20
|
+
'role': 'textbox',
|
|
21
|
+
'style': `min-height: ${PsPortableTextEditorService.minHeight(minRows)}`,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
extensions: PsPortableTextExtensionService.extensions({
|
|
25
|
+
classNames,
|
|
26
|
+
onLinkShortcut: () => setIsLinkOpen(true),
|
|
27
|
+
placeholder,
|
|
28
|
+
}),
|
|
29
|
+
immediatelyRender: true,
|
|
30
|
+
}, []);
|
|
31
|
+
const state = useEditorState({
|
|
32
|
+
editor,
|
|
33
|
+
selector: ({ editor: current }) => PsPortableTextCommandService.state(current),
|
|
34
|
+
});
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
editor.setEditable(!disabled, false);
|
|
37
|
+
}, [editor, disabled]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const update = () => {
|
|
40
|
+
const next = PsPortableTextConverterService.toBlocks(editor.getJSON());
|
|
41
|
+
lastValue.current = next;
|
|
42
|
+
onChange(next);
|
|
43
|
+
};
|
|
44
|
+
editor.on('update', update);
|
|
45
|
+
return () => {
|
|
46
|
+
editor.off('update', update);
|
|
47
|
+
};
|
|
48
|
+
}, [editor, onChange]);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (PsPortableTextEditorService.isSame(value, lastValue.current))
|
|
51
|
+
return;
|
|
52
|
+
lastValue.current = value;
|
|
53
|
+
editor.commands.setContent(PsPortableTextConverterService.toDocument(value), {
|
|
54
|
+
emitUpdate: false,
|
|
55
|
+
});
|
|
56
|
+
}, [editor, value]);
|
|
57
|
+
return (_jsx("div", { className: className, children: _jsxs(PsPortableTextCoreContext.Provider, { value: {
|
|
58
|
+
closeLink: () => setIsLinkOpen(false),
|
|
59
|
+
editor,
|
|
60
|
+
isLinkOpen,
|
|
61
|
+
openLink: () => setIsLinkOpen(true),
|
|
62
|
+
state,
|
|
63
|
+
}, children: [toolbar, _jsx(EditorContent, { editor: editor })] }) }));
|
|
64
|
+
};
|
|
@@ -1,31 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { useEffect,
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import { PsPortableTextCoreConfig } from '../constants/ps-portable-text-core-config';
|
|
6
|
-
import { PsPortableTextEditorService } from '../services/ps-portable-text-editor-service';
|
|
7
|
-
export const PsPortableTextCore = ({ className, disabled = false, editableClassName, fallback, minRows = 4, onChange, renderAnnotation, renderBlock, renderDecorator, renderPlaceholder, toolbar, value, }) => {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { PsPortableTextCoreEditor } from '@pallasoft/ps-input-components/portable-text-engine';
|
|
4
|
+
export const PsPortableTextCore = (props) => {
|
|
8
5
|
const [isMounted, setIsMounted] = useState(false);
|
|
9
|
-
const [version, setVersion] = useState(0);
|
|
10
|
-
const lastValue = useRef(value);
|
|
11
6
|
useEffect(() => {
|
|
12
7
|
setIsMounted(true);
|
|
13
8
|
}, []);
|
|
14
|
-
|
|
15
|
-
if (PsPortableTextEditorService.isSame(value, lastValue.current))
|
|
16
|
-
return;
|
|
17
|
-
lastValue.current = value;
|
|
18
|
-
setVersion((current) => current + 1);
|
|
19
|
-
}, [value]);
|
|
20
|
-
return (_jsx("div", { className: className, children: isMounted ? (_jsxs(EditorProvider, { initialConfig: {
|
|
21
|
-
initialValue: value,
|
|
22
|
-
readOnly: disabled,
|
|
23
|
-
schemaDefinition: PsPortableTextCoreConfig.schemaDefinition,
|
|
24
|
-
}, children: [_jsx(EventListenerPlugin, { on: (event) => {
|
|
25
|
-
if (event.type !== 'mutation')
|
|
26
|
-
return;
|
|
27
|
-
const next = Array.isArray(event.value) ? event.value : [];
|
|
28
|
-
lastValue.current = next;
|
|
29
|
-
onChange(next);
|
|
30
|
-
} }), toolbar, _jsx(PortableTextEditable, { className: editableClassName, readOnly: disabled, renderAnnotation: renderAnnotation, renderBlock: renderBlock, renderDecorator: renderDecorator, renderPlaceholder: renderPlaceholder, style: { minHeight: PsPortableTextEditorService.minHeight(minRows) } })] }, version)) : (fallback) }));
|
|
9
|
+
return isMounted ? (_jsx(PsPortableTextCoreEditor, { ...props })) : (_jsx("div", { className: props.className, children: props.fallback }));
|
|
31
10
|
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Common } from '@pallasoft/ps-models';
|
|
2
|
-
import { defineSchema } from '@portabletext/editor';
|
|
3
2
|
const Models = Common.PortableTextConfig;
|
|
4
3
|
export const PsPortableTextCoreConfig = {
|
|
5
4
|
linkAnnotation: Models.linkType,
|
|
6
5
|
mailtoPrefix: 'mailto:',
|
|
7
6
|
emailPattern: /^[^\s@/:]+@[^\s@/:]+\.[^\s@/:]+$/,
|
|
8
7
|
lineHeightRem: 1.5,
|
|
8
|
+
lineBreak: '\n',
|
|
9
|
+
defaultLinkProtocol: 'https',
|
|
10
|
+
keyPrefix: { block: 'b', link: 'l', span: 's' },
|
|
9
11
|
decorators: {
|
|
10
12
|
bold: Models.decorators[0],
|
|
11
13
|
code: Models.decorators[3],
|
|
@@ -14,19 +16,37 @@ export const PsPortableTextCoreConfig = {
|
|
|
14
16
|
},
|
|
15
17
|
styles: { blockquote: Models.styles[1], normal: Models.styles[0] },
|
|
16
18
|
listItems: { bullet: Models.listItems[0], number: Models.listItems[1] },
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
decoratorMarks: {
|
|
20
|
+
[Models.decorators[0]]: 'bold',
|
|
21
|
+
[Models.decorators[1]]: 'italic',
|
|
22
|
+
[Models.decorators[2]]: 'underline',
|
|
23
|
+
[Models.decorators[3]]: 'code',
|
|
24
|
+
},
|
|
25
|
+
listNodes: {
|
|
26
|
+
[Models.listItems[0]]: 'bulletList',
|
|
27
|
+
[Models.listItems[1]]: 'orderedList',
|
|
28
|
+
},
|
|
29
|
+
nodes: {
|
|
30
|
+
blockquote: 'blockquote',
|
|
31
|
+
bulletList: 'bulletList',
|
|
32
|
+
document: 'doc',
|
|
33
|
+
hardBreak: 'hardBreak',
|
|
34
|
+
listItem: 'listItem',
|
|
35
|
+
orderedList: 'orderedList',
|
|
36
|
+
paragraph: 'paragraph',
|
|
37
|
+
text: 'text',
|
|
38
|
+
},
|
|
39
|
+
linkMark: 'link',
|
|
40
|
+
linkShortcutExtension: 'psLinkShortcut',
|
|
41
|
+
listItemContent: 'paragraph (bulletList | orderedList)*',
|
|
42
|
+
blockquoteContent: 'paragraph+',
|
|
43
|
+
shortcuts: { link: 'Mod-k', nest: 'Tab', unnest: 'Shift-Tab' },
|
|
25
44
|
labels: {
|
|
26
45
|
bold: 'Bold',
|
|
27
46
|
bulletedList: 'Bulleted list',
|
|
28
47
|
cancel: 'Cancel',
|
|
29
48
|
code: 'Code',
|
|
49
|
+
editor: 'Text',
|
|
30
50
|
invalidLink: 'Enter a web address or email address',
|
|
31
51
|
italic: 'Italic',
|
|
32
52
|
link: 'Link',
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
import { PsPortableTextCommandService } from '../services/ps-portable-text-command-service';
|
|
3
|
+
export const PsPortableTextCoreContext = createContext({
|
|
4
|
+
closeLink: () => undefined,
|
|
5
|
+
editor: null,
|
|
6
|
+
isLinkOpen: false,
|
|
7
|
+
openLink: () => undefined,
|
|
8
|
+
state: PsPortableTextCommandService.state(null),
|
|
9
|
+
});
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
2
|
import { PsPortableTextEditorService } from '../services/ps-portable-text-editor-service';
|
|
3
|
-
export const usePsPortableTextLinkForm = ({ onClose, onSubmit, }) => {
|
|
3
|
+
export const usePsPortableTextLinkForm = ({ href, isOpen = false, onClose, onSubmit, }) => {
|
|
4
4
|
const [address, setAddress] = useState('');
|
|
5
5
|
const [hasError, setHasError] = useState(false);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (!isOpen)
|
|
8
|
+
return;
|
|
9
|
+
setAddress(href === undefined ? '' : href);
|
|
10
|
+
setHasError(false);
|
|
11
|
+
}, [isOpen]);
|
|
6
12
|
return {
|
|
7
13
|
address,
|
|
8
14
|
close: () => {
|
|
@@ -19,14 +25,14 @@ export const usePsPortableTextLinkForm = ({ onClose, onSubmit, }) => {
|
|
|
19
25
|
submit: (event) => {
|
|
20
26
|
event.preventDefault();
|
|
21
27
|
event.stopPropagation();
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
28
|
+
const normalized = PsPortableTextEditorService.normalizeLink(address);
|
|
29
|
+
if (normalized === null) {
|
|
24
30
|
setHasError(true);
|
|
25
31
|
return;
|
|
26
32
|
}
|
|
27
33
|
setAddress('');
|
|
28
34
|
setHasError(false);
|
|
29
|
-
onSubmit(
|
|
35
|
+
onSubmit(normalized);
|
|
30
36
|
},
|
|
31
37
|
};
|
|
32
38
|
};
|
|
@@ -1,54 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
import { PsPortableTextCoreContext } from '../contexts/ps-portable-text-core-context';
|
|
3
|
+
import { PsPortableTextCommandService } from '../services/ps-portable-text-command-service';
|
|
4
4
|
export const usePsPortableTextToolbar = () => {
|
|
5
|
-
const editor =
|
|
6
|
-
const isBold = useEditorSelector(editor, isActiveDecorator(PsPortableTextCoreConfig.decorators.bold));
|
|
7
|
-
const isItalic = useEditorSelector(editor, isActiveDecorator(PsPortableTextCoreConfig.decorators.italic));
|
|
8
|
-
const isUnderline = useEditorSelector(editor, isActiveDecorator(PsPortableTextCoreConfig.decorators.underline));
|
|
9
|
-
const isCode = useEditorSelector(editor, isActiveDecorator(PsPortableTextCoreConfig.decorators.code));
|
|
10
|
-
const isBulletedList = useEditorSelector(editor, isActiveListItem(PsPortableTextCoreConfig.listItems.bullet));
|
|
11
|
-
const isNumberedList = useEditorSelector(editor, isActiveListItem(PsPortableTextCoreConfig.listItems.number));
|
|
12
|
-
const isQuote = useEditorSelector(editor, isActiveStyle(PsPortableTextCoreConfig.styles.blockquote));
|
|
13
|
-
const isLink = useEditorSelector(editor, isActiveAnnotation(PsPortableTextCoreConfig.linkAnnotation));
|
|
14
|
-
const focus = () => editor.send({ type: 'focus' });
|
|
5
|
+
const { closeLink, editor, isLinkOpen, openLink, state } = useContext(PsPortableTextCoreContext);
|
|
15
6
|
return {
|
|
16
|
-
active:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
link: isLink,
|
|
22
|
-
numberedList: isNumberedList,
|
|
23
|
-
quote: isQuote,
|
|
24
|
-
underline: isUnderline,
|
|
25
|
-
},
|
|
26
|
-
addLink: (href) => {
|
|
27
|
-
editor.send({
|
|
28
|
-
type: 'annotation.add',
|
|
29
|
-
annotation: { name: PsPortableTextCoreConfig.linkAnnotation, value: { href } },
|
|
30
|
-
});
|
|
31
|
-
focus();
|
|
32
|
-
},
|
|
33
|
-
focus,
|
|
34
|
-
removeLink: () => {
|
|
35
|
-
editor.send({
|
|
36
|
-
type: 'annotation.remove',
|
|
37
|
-
annotation: { name: PsPortableTextCoreConfig.linkAnnotation },
|
|
38
|
-
});
|
|
39
|
-
focus();
|
|
40
|
-
},
|
|
41
|
-
toggleDecorator: (decorator) => {
|
|
42
|
-
editor.send({ type: 'decorator.toggle', decorator });
|
|
43
|
-
focus();
|
|
44
|
-
},
|
|
45
|
-
toggleListItem: (listItem) => {
|
|
46
|
-
editor.send({ type: 'list item.toggle', listItem });
|
|
47
|
-
focus();
|
|
48
|
-
},
|
|
49
|
-
toggleQuote: () => {
|
|
50
|
-
editor.send({ type: 'style.toggle', style: PsPortableTextCoreConfig.styles.blockquote });
|
|
51
|
-
focus();
|
|
7
|
+
active: state.active,
|
|
8
|
+
addLink: (href) => PsPortableTextCommandService.setLink(editor, href),
|
|
9
|
+
closeLink: () => {
|
|
10
|
+
closeLink();
|
|
11
|
+
PsPortableTextCommandService.focus(editor);
|
|
52
12
|
},
|
|
13
|
+
focus: () => PsPortableTextCommandService.focus(editor),
|
|
14
|
+
isLinkOpen,
|
|
15
|
+
linkHref: state.linkHref,
|
|
16
|
+
openLink,
|
|
17
|
+
removeLink: () => PsPortableTextCommandService.removeLink(editor),
|
|
18
|
+
toggleDecorator: (decorator) => PsPortableTextCommandService.toggleDecorator(editor, decorator),
|
|
19
|
+
toggleListItem: (listItem) => PsPortableTextCommandService.toggleListItem(editor, listItem),
|
|
20
|
+
toggleQuote: () => PsPortableTextCommandService.toggleQuote(editor),
|
|
53
21
|
};
|
|
54
22
|
};
|
|
@@ -2,5 +2,9 @@ export * from './components/ps-portable-text-core';
|
|
|
2
2
|
export * from './constants/ps-portable-text-core-config';
|
|
3
3
|
export * from './hooks/use-ps-portable-text-link-form';
|
|
4
4
|
export * from './hooks/use-ps-portable-text-toolbar';
|
|
5
|
+
export * from './interfaces/ps-portable-text-active-formats';
|
|
6
|
+
export * from './interfaces/ps-portable-text-core-class-names';
|
|
7
|
+
export * from './interfaces/ps-portable-text-core-props';
|
|
5
8
|
export * from './interfaces/ps-portable-text-editor-labels';
|
|
9
|
+
export * from './services/ps-portable-text-converter-service';
|
|
6
10
|
export * from './services/ps-portable-text-editor-service';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|