@wistia/ui 0.14.20 → 0.14.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.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  /*
3
- * @license @wistia/ui v0.14.20
3
+ * @license @wistia/ui v0.14.21
4
4
  *
5
5
  * Copyright (c) 2024-2025, Wistia, Inc. and its affiliates.
6
6
  *
@@ -11175,6 +11175,7 @@ var Input = forwardRef15(
11175
11175
  {
11176
11176
  $fullWidth: fullWidth,
11177
11177
  $monospace: monospace,
11178
+ "data-wui-input-container": true,
11178
11179
  children: [
11179
11180
  leftIconToDisplay ?? null,
11180
11181
  type === "multiline" ? /* @__PURE__ */ jsx247(
@@ -16891,10 +16892,480 @@ var ContextMenu = ({
16891
16892
  ) : null;
16892
16893
  };
16893
16894
 
16894
- // src/components/DataList/DataList.tsx
16895
+ // src/components/EditableText/EditableTextDisplay.tsx
16896
+ import { useContext as useContext13, useRef as useRef22, forwardRef as forwardRef36 } from "react";
16897
+ import styled104, { css as css48 } from "styled-components";
16898
+ import { isNotNil as isNotNil43 } from "@wistia/type-guards";
16899
+
16900
+ // src/components/EditableText/EditableTextRoot.tsx
16901
+ import {
16902
+ createContext as createContext12,
16903
+ useMemo as useMemo16,
16904
+ useState as useState25,
16905
+ useCallback as useCallback19,
16906
+ useId as useId6
16907
+ } from "react";
16908
+ import { isNonEmptyString as isNonEmptyString9 } from "@wistia/type-guards";
16895
16909
  import styled103 from "styled-components";
16896
16910
  import { jsx as jsx315 } from "react/jsx-runtime";
16897
- var StyledDataList = styled103.dl`
16911
+ var StyledEditableTextRoot = styled103.div`
16912
+ display: contents;
16913
+
16914
+ --wui-editable-text-padding: var(--wui-space-01);
16915
+ --wui-editable-text-border-radius: var(--wui-border-radius-01);
16916
+ `;
16917
+ var EditableTextContext = createContext12(null);
16918
+ var EditableTextRoot = ({
16919
+ children,
16920
+ defaultValue = "",
16921
+ value: controlledValue,
16922
+ onValueChange,
16923
+ onValueCommit,
16924
+ onValueRevert,
16925
+ onEditingChange,
16926
+ typographicVariant = "body2",
16927
+ submitMode = "both",
16928
+ readOnly = false,
16929
+ id,
16930
+ label,
16931
+ placeholder = "Click to edit this text",
16932
+ minLines = 1,
16933
+ maxLines,
16934
+ finalFocusEl,
16935
+ ...props
16936
+ }) => {
16937
+ const isControlled = controlledValue !== void 0;
16938
+ const [internalValue, setInternalValue] = useState25(defaultValue);
16939
+ const [originalValue, setOriginalValue] = useState25(defaultValue);
16940
+ const [isEditing, setIsEditing] = useState25(false);
16941
+ const value = isControlled ? controlledValue : internalValue;
16942
+ const generatedId = useId6();
16943
+ const computedId = isNonEmptyString9(id) ? id : `wistia-ui-editable-text-${generatedId}`;
16944
+ const handleSetIsEditing = useCallback19(
16945
+ (editing) => {
16946
+ if (editing && !isEditing) {
16947
+ setOriginalValue(value);
16948
+ }
16949
+ setIsEditing(editing);
16950
+ onEditingChange?.(editing);
16951
+ },
16952
+ [isEditing, value, onEditingChange]
16953
+ );
16954
+ const setValue = useCallback19(
16955
+ (newValue) => {
16956
+ if (!isControlled) {
16957
+ setInternalValue(newValue);
16958
+ }
16959
+ onValueChange?.(newValue);
16960
+ },
16961
+ [isControlled, onValueChange]
16962
+ );
16963
+ const context = useMemo16(() => {
16964
+ return {
16965
+ isEditing,
16966
+ setIsEditing: handleSetIsEditing,
16967
+ value,
16968
+ setValue,
16969
+ originalValue,
16970
+ onValueCommit,
16971
+ onValueRevert,
16972
+ typographicVariant,
16973
+ submitMode,
16974
+ readOnly,
16975
+ id: computedId,
16976
+ label,
16977
+ placeholder,
16978
+ minLines,
16979
+ maxLines,
16980
+ finalFocusEl
16981
+ };
16982
+ }, [
16983
+ isEditing,
16984
+ handleSetIsEditing,
16985
+ value,
16986
+ setValue,
16987
+ originalValue,
16988
+ onValueCommit,
16989
+ onValueRevert,
16990
+ typographicVariant,
16991
+ submitMode,
16992
+ readOnly,
16993
+ computedId,
16994
+ label,
16995
+ placeholder,
16996
+ minLines,
16997
+ maxLines,
16998
+ finalFocusEl
16999
+ ]);
17000
+ const getState = () => {
17001
+ if (readOnly) {
17002
+ return "read-only";
17003
+ }
17004
+ if (isEditing) {
17005
+ return "editing";
17006
+ }
17007
+ return "idle";
17008
+ };
17009
+ return /* @__PURE__ */ jsx315(
17010
+ StyledEditableTextRoot,
17011
+ {
17012
+ "data-testid": "editable-text-root",
17013
+ "data-wui-editable-text-root": true,
17014
+ "data-wui-editable-text-state": getState(),
17015
+ ...props,
17016
+ children: /* @__PURE__ */ jsx315(EditableTextContext.Provider, { value: context, children })
17017
+ }
17018
+ );
17019
+ };
17020
+
17021
+ // src/private/helpers/getTypographicStyles/getTypographicStyles.ts
17022
+ import { css as css47 } from "styled-components";
17023
+ var typographicVariantStyleMap = { ...variantStyleMap2, ...variantStyleMap };
17024
+ var getTypographicStyles = (variant) => {
17025
+ return css47`
17026
+ ${typographicVariantStyleMap[variant]}
17027
+ font-family: var(--font-family);
17028
+ font-size: var(--font-size);
17029
+ font-weight: var(--font-weight);
17030
+ line-height: var(--line-height);
17031
+ `;
17032
+ };
17033
+ var typographicVariantElementMap = { ...variantElementMap2, ...variantElementMap };
17034
+ var getDefaultTypographicElement = (variant) => {
17035
+ return typographicVariantElementMap[variant] ?? "span";
17036
+ };
17037
+
17038
+ // src/components/EditableText/EditableTextDisplay.tsx
17039
+ import { jsx as jsx316, jsxs as jsxs67 } from "react/jsx-runtime";
17040
+ var StyledEditableTextDisplay = styled104.div`
17041
+ ${({ $typographicVariant }) => getTypographicStyles($typographicVariant)}
17042
+ padding: var(--wui-editable-text-padding);
17043
+ border-radius: var(--wui-editable-text-border-radius);
17044
+ margin: 0;
17045
+ transition: all var(--wui-motion-duration-02) var(--wui-motion-ease);
17046
+ ${({ $maxLines }) => {
17047
+ if (isNotNil43($maxLines)) {
17048
+ return css48`
17049
+ ${ellipsisStyle};
17050
+ ${lineClampCss($maxLines)};
17051
+ `;
17052
+ }
17053
+ return void 0;
17054
+ }}
17055
+ ${({ $minLines }) => isNotNil43($minLines) && css48`
17056
+ min-height: calc(${$minLines}lh + calc(var(--wui-editable-text-padding) * 2));
17057
+ `}
17058
+ word-break: break-word;
17059
+
17060
+ &[data-wui-editable-text-display='placeholder'] {
17061
+ color: var(--wui-color-text-secondary);
17062
+ }
17063
+
17064
+ &:has(button) {
17065
+ user-select: none;
17066
+ cursor: pointer;
17067
+
17068
+ &:hover,
17069
+ &:focus-within {
17070
+ background-color: var(--wui-color-bg-surface-hover);
17071
+ }
17072
+ }
17073
+ `;
17074
+ var EditableTextDisplayComponent = forwardRef36(
17075
+ ({ asTrigger, renderAs, ...props }, ref) => {
17076
+ const context = useContext13(EditableTextContext);
17077
+ if (!context) {
17078
+ throw new Error("EditableTextDisplay must be used within an EditableTextRoot context");
17079
+ }
17080
+ const { value, typographicVariant, setIsEditing, placeholder, maxLines, isEditing, minLines } = context;
17081
+ const triggerButtonRef = useRef22(null);
17082
+ const handleTriggerClick = () => {
17083
+ setIsEditing(true);
17084
+ };
17085
+ const elementType = renderAs ?? getDefaultTypographicElement(typographicVariant);
17086
+ const displayText = value.length > 0 ? value : placeholder;
17087
+ const isPlaceholderVisible = value.length === 0 && !!placeholder;
17088
+ if (isEditing) {
17089
+ return null;
17090
+ }
17091
+ if (asTrigger && !context.readOnly) {
17092
+ return /* @__PURE__ */ jsx316(ClickRegion, { targetRef: triggerButtonRef, children: /* @__PURE__ */ jsxs67(
17093
+ StyledEditableTextDisplay,
17094
+ {
17095
+ ref,
17096
+ $maxLines: maxLines,
17097
+ $minLines: minLines,
17098
+ $typographicVariant: typographicVariant,
17099
+ as: elementType,
17100
+ "data-wui-editable-text-display": isPlaceholderVisible ? "placeholder" : "value",
17101
+ ...props,
17102
+ children: [
17103
+ displayText,
17104
+ /* @__PURE__ */ jsx316(
17105
+ "button",
17106
+ {
17107
+ ref: triggerButtonRef,
17108
+ onClick: handleTriggerClick,
17109
+ style: { ...visuallyHiddenStyle },
17110
+ type: "button",
17111
+ children: "Edit text"
17112
+ }
17113
+ )
17114
+ ]
17115
+ }
17116
+ ) });
17117
+ }
17118
+ return /* @__PURE__ */ jsx316(
17119
+ StyledEditableTextDisplay,
17120
+ {
17121
+ ref,
17122
+ $maxLines: maxLines,
17123
+ $minLines: minLines,
17124
+ $typographicVariant: typographicVariant,
17125
+ as: elementType,
17126
+ "data-placeholder-visible": isPlaceholderVisible || void 0,
17127
+ "data-wui-editable-text-display": true,
17128
+ ...props,
17129
+ children: displayText
17130
+ }
17131
+ );
17132
+ }
17133
+ );
17134
+ EditableTextDisplayComponent.displayName = "EditableTextDisplay_UI";
17135
+ var EditableTextDisplay = makePolymorphic(
17136
+ EditableTextDisplayComponent
17137
+ );
17138
+
17139
+ // src/components/EditableText/EditableTextInput.tsx
17140
+ import { useContext as useContext14, useEffect as useEffect21, useRef as useRef23 } from "react";
17141
+ import styled105 from "styled-components";
17142
+ import { isNotNil as isNotNil44 } from "@wistia/type-guards";
17143
+ import { jsx as jsx317 } from "react/jsx-runtime";
17144
+ var StyledInput2 = styled105(Input)`
17145
+ && {
17146
+ ${({ $minLines }) => isNotNil44($minLines) && `min-height: calc(${$minLines}lh + calc(var(--wui-editable-text-padding) * 2));`}
17147
+ ${({ $maxLines }) => isNotNil44($maxLines) && `max-height: calc(${$maxLines}lh + calc(var(--wui-editable-text-padding) * 2));`}
17148
+ ${({ $typographicVariant }) => getTypographicStyles($typographicVariant)}
17149
+ padding: var(--wui-editable-text-padding);
17150
+ border-radius: var(--wui-editable-text-border-radius);
17151
+ background-color: var(--wui-color-bg-surface);
17152
+ }
17153
+ `;
17154
+ var EditableTextInput = (props) => {
17155
+ const context = useContext14(EditableTextContext);
17156
+ if (!context) {
17157
+ throw new Error("EditableTextInput must be used within an EditableTextRoot context");
17158
+ }
17159
+ const {
17160
+ isEditing,
17161
+ value,
17162
+ setValue,
17163
+ onValueCommit,
17164
+ setIsEditing,
17165
+ typographicVariant,
17166
+ submitMode,
17167
+ originalValue,
17168
+ onValueRevert,
17169
+ id,
17170
+ placeholder,
17171
+ minLines,
17172
+ maxLines,
17173
+ finalFocusEl
17174
+ } = context;
17175
+ const inputRef = useRef23(null);
17176
+ useEffect21(() => {
17177
+ if (inputRef.current) {
17178
+ if (isEditing) {
17179
+ const element = inputRef.current;
17180
+ const { style } = element;
17181
+ style.height = "0px";
17182
+ const { scrollHeight } = element;
17183
+ style.height = `${scrollHeight}px`;
17184
+ }
17185
+ if (isEditing) {
17186
+ inputRef.current.focus();
17187
+ }
17188
+ }
17189
+ }, [value, isEditing]);
17190
+ const handleChange = (event) => {
17191
+ setValue(event.target.value);
17192
+ };
17193
+ const handleKeyDown = (event) => {
17194
+ if ((submitMode === "enter" || submitMode === "both") && event.key === "Enter" && !event.shiftKey) {
17195
+ event.preventDefault();
17196
+ onValueCommit?.(value);
17197
+ setIsEditing(false);
17198
+ setTimeout(() => {
17199
+ const element = finalFocusEl?.();
17200
+ if (element) {
17201
+ element.focus();
17202
+ }
17203
+ }, 0);
17204
+ }
17205
+ if (event.key === "Escape") {
17206
+ event.preventDefault();
17207
+ setValue(originalValue);
17208
+ onValueRevert?.(originalValue);
17209
+ setIsEditing(false);
17210
+ setTimeout(() => {
17211
+ const element = finalFocusEl?.();
17212
+ if (element) {
17213
+ element.focus();
17214
+ }
17215
+ }, 0);
17216
+ }
17217
+ };
17218
+ const handleBlur2 = () => {
17219
+ if (submitMode === "blur" || submitMode === "both") {
17220
+ onValueCommit?.(value);
17221
+ setIsEditing(false);
17222
+ setTimeout(() => {
17223
+ const element = finalFocusEl?.();
17224
+ if (element) {
17225
+ element.focus();
17226
+ }
17227
+ }, 0);
17228
+ }
17229
+ };
17230
+ if (!isEditing) return null;
17231
+ return /* @__PURE__ */ jsx317(
17232
+ StyledInput2,
17233
+ {
17234
+ ref: inputRef,
17235
+ $maxLines: maxLines ?? "infinity",
17236
+ $minLines: minLines,
17237
+ $typographicVariant: typographicVariant,
17238
+ "data-wui-editable-text-input": true,
17239
+ id,
17240
+ onBlur: handleBlur2,
17241
+ onChange: handleChange,
17242
+ onKeyDown: handleKeyDown,
17243
+ placeholder,
17244
+ type: "multiline",
17245
+ value,
17246
+ ...props
17247
+ }
17248
+ );
17249
+ };
17250
+
17251
+ // src/components/EditableText/EditableTextLabel.tsx
17252
+ import { useContext as useContext15 } from "react";
17253
+ import { jsx as jsx318 } from "react/jsx-runtime";
17254
+ var EditableTextLabel = ({ ...props }) => {
17255
+ const context = useContext15(EditableTextContext);
17256
+ if (!context) {
17257
+ throw new Error("EditableTextLabel must be used within an EditableTextRoot context");
17258
+ }
17259
+ const { id, label } = context;
17260
+ return /* @__PURE__ */ jsx318(
17261
+ Label,
17262
+ {
17263
+ htmlFor: id,
17264
+ ...props,
17265
+ children: label
17266
+ }
17267
+ );
17268
+ };
17269
+
17270
+ // src/components/EditableText/EditableText.tsx
17271
+ import { jsx as jsx319, jsxs as jsxs68 } from "react/jsx-runtime";
17272
+ var EditableText = ({ hideLabel = true, ...props }) => /* @__PURE__ */ jsxs68(EditableTextRoot, { ...props, children: [
17273
+ /* @__PURE__ */ jsx319(EditableTextLabel, { screenReaderOnly: hideLabel }),
17274
+ /* @__PURE__ */ jsx319(EditableTextInput, {}),
17275
+ /* @__PURE__ */ jsx319(EditableTextDisplay, { asTrigger: true })
17276
+ ] });
17277
+ EditableText.displayName = "EditableText_UI";
17278
+
17279
+ // src/components/EditableText/EditableTextSubmitButton.tsx
17280
+ import { useContext as useContext16, Children as Children8, cloneElement as cloneElement6 } from "react";
17281
+ var EditableTextSubmitButton = ({
17282
+ /**
17283
+ * A submit button, typically a [Button]() that will commit the value when clicked.
17284
+ */
17285
+ children
17286
+ }) => {
17287
+ const context = useContext16(EditableTextContext);
17288
+ if (!context) {
17289
+ throw new Error("EditableTextSubmitButton must be used within an EditableTextRoot context");
17290
+ }
17291
+ const { setIsEditing, value, onValueCommit, finalFocusEl, isEditing } = context;
17292
+ const handleClick = () => {
17293
+ onValueCommit?.(value);
17294
+ setIsEditing(false);
17295
+ setTimeout(() => {
17296
+ const element = finalFocusEl?.();
17297
+ if (element) {
17298
+ element.focus();
17299
+ }
17300
+ }, 0);
17301
+ };
17302
+ const onlyChild = Children8.only(children);
17303
+ const triggerProps = {
17304
+ onClick: handleClick,
17305
+ "data-wui-editable-text-submit": true
17306
+ };
17307
+ if (!isEditing) return null;
17308
+ return cloneElement6(onlyChild, triggerProps);
17309
+ };
17310
+
17311
+ // src/components/EditableText/EditableTextCancelButton.tsx
17312
+ import { useContext as useContext17, Children as Children9, cloneElement as cloneElement7 } from "react";
17313
+ var EditableTextCancelButton = ({
17314
+ children
17315
+ }) => {
17316
+ const context = useContext17(EditableTextContext);
17317
+ if (!context) {
17318
+ throw new Error("EditableTextCancelButton must be used within an EditableTextRoot context");
17319
+ }
17320
+ const { setIsEditing, originalValue, setValue, onValueRevert, finalFocusEl, isEditing } = context;
17321
+ const handleClick = () => {
17322
+ setValue(originalValue);
17323
+ onValueRevert?.(originalValue);
17324
+ setIsEditing(false);
17325
+ setTimeout(() => {
17326
+ const element = finalFocusEl?.();
17327
+ if (element) {
17328
+ element.focus();
17329
+ }
17330
+ }, 0);
17331
+ };
17332
+ const onlyChild = Children9.only(children);
17333
+ const triggerProps = {
17334
+ onClick: handleClick,
17335
+ "data-wui-editable-text-cancel": true
17336
+ };
17337
+ if (!isEditing) return null;
17338
+ return cloneElement7(onlyChild, triggerProps);
17339
+ };
17340
+
17341
+ // src/components/EditableText/EditableTextTrigger.tsx
17342
+ import { useContext as useContext18, Children as Children10, cloneElement as cloneElement8 } from "react";
17343
+ var EditableTextTrigger = ({
17344
+ children,
17345
+ ...props
17346
+ }) => {
17347
+ const context = useContext18(EditableTextContext);
17348
+ if (!context) {
17349
+ throw new Error("EditableTextTrigger must be used within an EditableTextRoot context");
17350
+ }
17351
+ const { setIsEditing, isEditing } = context;
17352
+ const handleClick = () => {
17353
+ setIsEditing(true);
17354
+ };
17355
+ const onlyChild = Children10.only(children);
17356
+ const triggerProps = {
17357
+ onClick: handleClick,
17358
+ "data-wui-editable-text-trigger": true,
17359
+ ...props
17360
+ };
17361
+ if (isEditing) return null;
17362
+ return cloneElement8(onlyChild, triggerProps);
17363
+ };
17364
+
17365
+ // src/components/DataList/DataList.tsx
17366
+ import styled106 from "styled-components";
17367
+ import { jsx as jsx320 } from "react/jsx-runtime";
17368
+ var StyledDataList = styled106.dl`
16898
17369
  display: grid;
16899
17370
  grid-template-columns: auto 1fr;
16900
17371
  column-gap: var(--wui-space-02);
@@ -16922,7 +17393,7 @@ var DataList = ({
16922
17393
  labelProminence = "primary",
16923
17394
  ...props
16924
17395
  }) => {
16925
- return /* @__PURE__ */ jsx315(
17396
+ return /* @__PURE__ */ jsx320(
16926
17397
  StyledDataList,
16927
17398
  {
16928
17399
  role: "list",
@@ -16945,9 +17416,9 @@ var DataListItem = ({ children }) => {
16945
17416
  DataListItem.displayName = "DataListItem_UI";
16946
17417
 
16947
17418
  // src/components/DataList/DataListItemLabel.tsx
16948
- import { jsx as jsx316 } from "react/jsx-runtime";
17419
+ import { jsx as jsx321 } from "react/jsx-runtime";
16949
17420
  var DataListItemLabel = (props) => {
16950
- return /* @__PURE__ */ jsx316(
17421
+ return /* @__PURE__ */ jsx321(
16951
17422
  Text,
16952
17423
  {
16953
17424
  variant: "label4",
@@ -16959,9 +17430,9 @@ var DataListItemLabel = (props) => {
16959
17430
  DataListItemLabel.displayName = "DataListItemLabel_UI";
16960
17431
 
16961
17432
  // src/components/DataList/DataListItemValue.tsx
16962
- import { jsx as jsx317 } from "react/jsx-runtime";
17433
+ import { jsx as jsx322 } from "react/jsx-runtime";
16963
17434
  var DataListItemValue = (props) => {
16964
- return /* @__PURE__ */ jsx317(
17435
+ return /* @__PURE__ */ jsx322(
16965
17436
  Text,
16966
17437
  {
16967
17438
  variant: "body3",
@@ -17015,6 +17486,15 @@ export {
17015
17486
  DataListItemValue,
17016
17487
  Divider,
17017
17488
  EditableHeading,
17489
+ EditableText,
17490
+ EditableTextCancelButton,
17491
+ EditableTextContext,
17492
+ EditableTextDisplay,
17493
+ EditableTextInput,
17494
+ EditableTextLabel,
17495
+ EditableTextRoot,
17496
+ EditableTextSubmitButton,
17497
+ EditableTextTrigger,
17018
17498
  Ellipsis,
17019
17499
  FileAmountLimitValidator,
17020
17500
  FileSizeValidator,